From e50e906866a706c99a5fa0f312d96c034b2602f7 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 6 May 2026 07:36:09 +0000 Subject: [PATCH] fix(simple): dedupe exit retries per scan --- backend/src/index.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backend/src/index.ts b/backend/src/index.ts index bfa0034..0fe5de7 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -273,6 +273,7 @@ async function main() { simpleWorkerRunning = true; try { const entries = (await listManualEntries()).filter((entry) => entry.active && isSimpleWorkflowEntry(entry)); + const processedSimpleExitKeys = new Set(); for (const entry of entries) { const symbol = String(entry.symbol || '').trim().toUpperCase(); if (!symbol) continue; @@ -339,6 +340,22 @@ async function main() { } const linkedTradeId = String(entry.linked_trade_id || '').trim(); + const exitDedupKey = linkedTradeId ? `${symbol}::${linkedTradeId}` : symbol; + if (processedSimpleExitKeys.has(exitDedupKey)) { + continue; + } + + const exitLifecycle = ctx.executor.getExitLifecycle(symbol); + if ( + exitLifecycle.state === 'initiated' + || exitLifecycle.state === 'order_placed' + || exitLifecycle.state === 'verifying' + || exitLifecycle.state === 'quarantined' + ) { + processedSimpleExitKeys.add(exitDedupKey); + continue; + } + const activePosition = linkedTradeId ? ctx.executor.getActivePosition(symbol, linkedTradeId) : ctx.executor.getActivePosition(symbol); @@ -370,9 +387,11 @@ async function main() { const exitResult = await ctx.manualTrader.executeExit(symbol, currentPrice, 'Simple target hit', linkedTradeId || undefined); if (!exitResult.success) { logger.warn(`[SimpleWorker] Exit trigger failed for ${symbol}: ${exitResult.error || 'unknown error'}`); + processedSimpleExitKeys.add(exitDedupKey); continue; } + processedSimpleExitKeys.add(exitDedupKey); await saveManualEntryForUser(entry.user_id, { ...entry, profile_id: entry.profile_id || ctx.profileId,