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:
@@ -408,8 +408,19 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
|
||||
// Get current price for the blocked signal record
|
||||
const currentPrice = await getCurrentPrice(body.symbol, fallbackPrice)
|
||||
|
||||
// CRITICAL FIX (Dec 12, 2025): Smart validation integration
|
||||
// Check if signal quality is in validation range (50-89)
|
||||
const isInValidationRange = qualityScore.score >= 50 && qualityScore.score < 90
|
||||
|
||||
// Save blocked signal to database for future analysis
|
||||
if (currentPrice > 0) {
|
||||
// SMART VALIDATION QUEUE (Nov 30, 2025 - FIXED Dec 12, 2025)
|
||||
// Queue marginal quality signals (50-89) for validation instead of hard-blocking
|
||||
const blockReason = isInValidationRange ? 'SMART_VALIDATION_QUEUED' : 'QUALITY_SCORE_TOO_LOW'
|
||||
const blockDetails = isInValidationRange
|
||||
? `Score: ${qualityScore.score}/${minQualityScore} - Queued for validation (will enter if +0.3%, abandon if -1.0%)`
|
||||
: `Score: ${qualityScore.score}/${minQualityScore} - ${qualityScore.reasons.join(', ')}`
|
||||
|
||||
await createBlockedSignal({
|
||||
symbol: body.symbol,
|
||||
direction: body.direction,
|
||||
@@ -421,41 +432,41 @@ export async function POST(request: NextRequest): Promise<NextResponse<RiskCheck
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
signalQualityScore: qualityScore.score,
|
||||
signalQualityVersion: 'v4', // Update this when scoring logic changes
|
||||
signalQualityVersion: 'v4',
|
||||
scoreBreakdown: { reasons: qualityScore.reasons },
|
||||
minScoreRequired: minQualityScore, // Use direction-specific threshold
|
||||
blockReason: 'QUALITY_SCORE_TOO_LOW',
|
||||
blockDetails: `Score: ${qualityScore.score}/${minQualityScore} - ${qualityScore.reasons.join(', ')}`,
|
||||
minScoreRequired: minQualityScore,
|
||||
blockReason: blockReason,
|
||||
blockDetails: blockDetails,
|
||||
indicatorVersion: body.indicatorVersion || 'v5',
|
||||
})
|
||||
|
||||
// SMART VALIDATION QUEUE (Nov 30, 2025)
|
||||
// Queue marginal quality signals (50-89) for validation instead of hard-blocking
|
||||
const validationQueue = getSmartValidationQueue()
|
||||
|
||||
// CRITICAL FIX (Dec 1, 2025): Normalize TradingView symbol format to Drift format
|
||||
// Bug: Market data cache uses "SOL-PERP" but TradingView sends "SOLUSDT"
|
||||
// Without normalization, validation queue can't find matching price data
|
||||
// Result: Wrong/stale price shown in Telegram abandonment notifications
|
||||
const normalizedSymbol = normalizeTradingViewSymbol(body.symbol)
|
||||
|
||||
const queued = await validationQueue.addSignal({
|
||||
blockReason: 'QUALITY_SCORE_TOO_LOW',
|
||||
symbol: normalizedSymbol, // Use normalized format for cache lookup
|
||||
direction: body.direction,
|
||||
originalPrice: currentPrice,
|
||||
qualityScore: qualityScore.score,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
indicatorVersion: body.indicatorVersion || 'v5',
|
||||
timeframe: body.timeframe || '5',
|
||||
})
|
||||
|
||||
if (queued) {
|
||||
console.log(`🧠 Signal queued for smart validation: ${normalizedSymbol} ${body.direction} (quality ${qualityScore.score})`)
|
||||
// Add to validation queue if in range
|
||||
if (isInValidationRange) {
|
||||
const validationQueue = getSmartValidationQueue()
|
||||
|
||||
// CRITICAL FIX (Dec 1, 2025): Normalize TradingView symbol format to Drift format
|
||||
const normalizedSymbol = normalizeTradingViewSymbol(body.symbol)
|
||||
|
||||
const queued = await validationQueue.addSignal({
|
||||
blockReason: 'SMART_VALIDATION_QUEUED',
|
||||
symbol: normalizedSymbol,
|
||||
direction: body.direction,
|
||||
originalPrice: currentPrice,
|
||||
qualityScore: qualityScore.score,
|
||||
atr: body.atr,
|
||||
adx: body.adx,
|
||||
rsi: body.rsi,
|
||||
volumeRatio: body.volumeRatio,
|
||||
pricePosition: body.pricePosition,
|
||||
indicatorVersion: body.indicatorVersion || 'v5',
|
||||
timeframe: body.timeframe || '5',
|
||||
})
|
||||
|
||||
if (queued) {
|
||||
console.log(`🧠 Signal queued for smart validation: ${normalizedSymbol} ${body.direction} (quality ${qualityScore.score})`)
|
||||
}
|
||||
} else {
|
||||
console.log(`❌ Signal quality too low for validation: ${qualityScore.score} (need 50-89 range)`)
|
||||
}
|
||||
} else {
|
||||
console.warn('⚠️ Skipping blocked signal save: price unavailable (quality block)')
|
||||
|
||||
Reference in New Issue
Block a user