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

@@ -900,6 +900,8 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
// CRITICAL FIX: Place on-chain TP/SL orders BEFORE adding to Position Manager
// This prevents race condition where Position Manager detects "external closure"
// while orders are still being placed, leaving orphaned stop loss orders
// TP2 is a software trigger only do not place on-chain TP2 orders so the runner remains intact
const effectiveTp2SizePercent = 0
let exitOrderSignatures: string[] = []
try {
console.log('🔍 DEBUG: About to call placeExitOrders()...')
@@ -921,7 +923,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
tp2Price,
stopLossPrice,
tp1SizePercent: config.takeProfit1SizePercent ?? 75,
tp2SizePercent: config.takeProfit2SizePercent ?? 0, // 0 = activate trailing stop, don't close
tp2SizePercent: effectiveTp2SizePercent, // Always trigger-only: trailing activation only
direction: body.direction,
// Dual stop parameters
useDualStops: config.useDualStops,
@@ -950,7 +952,7 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
exitOrderSignatures = exitRes.signatures || []
// BUG #76 FIX: Validate expected signature count
const expectedCount = config.useDualStops ? 4 : 3 // TP1 + TP2 + (soft+hard OR single SL)
const expectedCount = exitRes.expectedOrders ?? (config.useDualStops ? 3 : 2)
if (exitOrderSignatures.length < expectedCount) {
console.error(`❌ CRITICAL: Missing exit orders!`)
console.error(` Expected: ${expectedCount} signatures (TP1 + TP2 + ${config.useDualStops ? 'Soft SL + Hard SL' : 'SL'})`)
@@ -1025,14 +1027,14 @@ export async function POST(request: NextRequest): Promise<NextResponse<ExecuteTr
takeProfit1Price: tp1Price,
takeProfit2Price: tp2Price,
tp1SizePercent: config.takeProfit1SizePercent ?? 75,
tp2SizePercent: config.takeProfit2SizePercent ?? 0, // Use ?? to allow 0 for runner system
tp2SizePercent: effectiveTp2SizePercent, // Use ?? to allow 0 for runner system
configSnapshot: config,
entryOrderTx: openResult.transactionSignature!,
tp1OrderTx: exitOrderSignatures[0],
tp2OrderTx: exitOrderSignatures[1],
slOrderTx: config.useDualStops ? undefined : exitOrderSignatures[2],
softStopOrderTx: config.useDualStops ? exitOrderSignatures[2] : undefined,
hardStopOrderTx: config.useDualStops ? exitOrderSignatures[3] : undefined,
tp2OrderTx: undefined, // TP2 is software-only trigger; no on-chain TP2 order
slOrderTx: config.useDualStops ? undefined : exitOrderSignatures[1],
softStopOrderTx: config.useDualStops ? exitOrderSignatures[1] : undefined,
hardStopOrderTx: config.useDualStops ? exitOrderSignatures[2] : undefined,
softStopPrice,
hardStopPrice,
signalSource: body.timeframe === 'manual' ? 'manual' : 'tradingview', // Identify manual Telegram trades