Skip to content

Commit 9dc713b

Browse files
refactor(webhook): move confirmation to immediately after dedupe acceptance; remove duplicate confirmation block
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent b40b57e commit 9dc713b

1 file changed

Lines changed: 38 additions & 30 deletions

File tree

webhook_server_fastapi.py

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3537,6 +3537,43 @@ def webhook(payload: WebhookPayload):
35373537
}
35383538
else:
35393539
logger.info(f"[{request_id}] SIGNAL DEDUPE: signal_id={signal_id}, signal={sig_for_dedupe} - ACCEPTED")
3540+
# ─────────────────────────────────────────────
3541+
# CONFIRMATION (Debounce) - run IMMEDIATELY AFTER dedupe acceptance,
3542+
# and BEFORE Session / MQ checks (ensures ordering: SIGNAL ACCEPTED -> confirmation -> Session Gate)
3543+
# ─────────────────────────────────────────────
3544+
try:
3545+
if getattr(settings, "WINRATE_UPGRADE_ENABLED", False) and getattr(settings, "REQUIRE_CONFIRMATION", False):
3546+
# Build confirmation key: prefer explicit signal_id; fallback to hashed logging id + signal
3547+
if payload.signal_id:
3548+
conf_key = f"{payload.signal_id}|{sig_for_dedupe}"
3549+
else:
3550+
# signal_id_for_logging may be None here; use fallback hash if needed
3551+
payload_hash = _hash_payload(payload.model_dump())
3552+
fallback_id = f"hash_{payload_hash}"
3553+
conf_key = f"{fallback_id}|{sig_for_dedupe}"
3554+
3555+
confirmed, _ = _confirmation_store.pop_if_confirmed(
3556+
conf_key,
3557+
delay=getattr(settings, "CONFIRMATION_DELAY_SECONDS", 60),
3558+
ttl=getattr(settings, "CONFIRMATION_TTL_SECONDS", 180),
3559+
)
3560+
if not confirmed:
3561+
# mark pending (idempotent)
3562+
_confirmation_store.mark_pending(conf_key, {"first_seen": time.time(), "request_id": request_id})
3563+
logger.info(f"[{request_id}] confirmation_pending: key={conf_key}")
3564+
return {
3565+
"ok": True,
3566+
"status": "pending_confirmation",
3567+
"reason": "confirmation_pending",
3568+
"message": "Signal stored, waiting for confirmation",
3569+
"confirmation_key": conf_key,
3570+
"mode": get_trading_mode_str(),
3571+
}
3572+
else:
3573+
logger.info(f"[{request_id}] confirmation_passed: key={conf_key}")
3574+
except Exception:
3575+
# Fail-safe: if confirmation store has issues, continue processing (do not block pipeline)
3576+
logger.exception(f"[{request_id}] confirmation_store error, continuing without confirmation")
35403577
else:
35413578
logger.warning(f"[{request_id}] SIGNAL DEDUPE: signal_id={signal_id} but invalid signal={sig_for_dedupe}, skipping dedupe check")
35423579
else:
@@ -3573,36 +3610,7 @@ def webhook(payload: WebhookPayload):
35733610
f"MODE: {mode} | KIND: {signal_kind} (TradingView signal tracking)"
35743611
)
35753612

3576-
# ─────────────────────────────────────────────
3577-
# CONFIRMATION (Debounce) - run BEFORE Session / MQ checks
3578-
# ─────────────────────────────────────────────
3579-
if getattr(settings, "WINRATE_UPGRADE_ENABLED", False) and getattr(settings, "REQUIRE_CONFIRMATION", False):
3580-
# Build confirmation key: prefer explicit signal_id; fallback to hashed logging id + signal
3581-
conf_key = None
3582-
if payload.signal_id:
3583-
conf_key = f"{payload.signal_id}|{sig_for_dedupe}"
3584-
else:
3585-
conf_key = f"{signal_id_for_logging}|{sig_for_dedupe}"
3586-
3587-
confirmed, _ = _confirmation_store.pop_if_confirmed(
3588-
conf_key,
3589-
delay=getattr(settings, "CONFIRMATION_DELAY_SECONDS", 60),
3590-
ttl=getattr(settings, "CONFIRMATION_TTL_SECONDS", 180),
3591-
)
3592-
if not confirmed:
3593-
# mark pending (idempotent)
3594-
_confirmation_store.mark_pending(conf_key, {"first_seen": time.time(), "request_id": request_id})
3595-
logger.info(f"[{request_id}] confirmation_pending: key={conf_key}")
3596-
return {
3597-
"ok": True,
3598-
"status": "pending_confirmation",
3599-
"reason": "confirmation_pending",
3600-
"message": "Signal stored, waiting for confirmation",
3601-
"confirmation_key": conf_key,
3602-
"mode": get_trading_mode_str(),
3603-
}
3604-
else:
3605-
logger.info(f"[{request_id}] confirmation_passed: key={conf_key}")
3613+
# (confirmation logic moved to run immediately after dedupe acceptance to ensure correct ordering)
36063614

36073615
# Robustes Parsing und Normalisierung
36083616
# Note: sig_for_dedupe was already parsed above for dedupe check

0 commit comments

Comments
 (0)