feat: Deploy HA auto-failover with database promotion

- Enhanced DNS failover monitor on secondary (72.62.39.24)
- Auto-promotes database: pg_ctl promote on failover
- Creates DEMOTED flag on primary via SSH (split-brain protection)
- Telegram notifications with database promotion status
- Startup safety script ready (integration pending)
- 90-second automatic recovery vs 10-30 min manual
- Zero-cost 95% enterprise HA benefit

Status: DEPLOYED and MONITORING (14:52 CET)
Next: Controlled failover test during maintenance
This commit is contained in:
mindesbunister
2025-12-12 15:54:03 +01:00
parent 7ff5c5b3a4
commit d637aac2d7
25 changed files with 1071 additions and 170 deletions

View File

@@ -16,10 +16,35 @@ import { ActiveTrade } from '../../../lib/trading/position-manager'
import { createMockTrade } from '../../helpers/trade-factory'
// Mock dependencies
jest.mock('../../../lib/drift/client')
const mockDriftService = {
isInitialized: true,
getPosition: jest.fn().mockResolvedValue({ size: 0 }),
getClient: jest.fn(() => ({})),
}
jest.mock('../../../lib/drift/client', () => ({
getDriftService: jest.fn(() => mockDriftService),
}))
jest.mock('../../../lib/drift/orders', () => ({
placeExitOrders: jest.fn(async () => ({
success: true,
signatures: [],
expectedOrders: 0,
placedOrders: 0,
})),
closePosition: jest.fn(async () => ({ success: true })),
cancelAllOrders: jest.fn(async () => ({ success: true })),
}))
jest.mock('../../../lib/pyth/price-monitor')
jest.mock('../../../lib/database/trades')
jest.mock('../../../lib/notifications/telegram')
jest.mock('../../../lib/utils/persistent-logger', () => ({
logCriticalError: jest.fn(),
logError: jest.fn(),
logWarning: jest.fn(),
}))
describe('Position Manager Monitoring Verification', () => {
let manager: PositionManager
@@ -27,6 +52,7 @@ describe('Position Manager Monitoring Verification', () => {
beforeEach(() => {
jest.clearAllMocks()
mockDriftService.getPosition.mockResolvedValue({ size: 1 })
// Mock Pyth price monitor
mockPriceMonitor = {
@@ -41,6 +67,12 @@ describe('Position Manager Monitoring Verification', () => {
manager = new PositionManager()
})
afterEach(async () => {
if ((manager as any)?.isMonitoring) {
await (manager as any).stopMonitoring?.()
}
})
describe('CRITICAL: Monitoring Actually Starts', () => {
it('should start Pyth price monitor when trade added', async () => {
const trade = createMockTrade({ direction: 'long', symbol: 'SOL-PERP' })