fix: outbox consumer_inbox idempotency logic + tenant_plugin_activation per-tenant check

This commit is contained in:
Agent Zero
2026-07-29 13:02:33 +02:00
parent 0f4e51c4b3
commit 648d8d89d6
4 changed files with 89 additions and 8 deletions
+17 -1
View File
@@ -179,6 +179,18 @@ async def process_outbox_batch(
payload_dict.setdefault("_event_name", event_name)
payload_dict.setdefault("_event_timestamp", datetime.now(timezone.utc).isoformat())
# Idempotency check: has this event already been processed? (P1.5 fix)
already_processed = await db.execute(
text("SELECT 1 FROM consumer_inbox WHERE event_id = :eid AND status = 'processed' LIMIT 1"),
{"eid": str(event_id)},
)
if already_processed.first():
# Event was already processed by all consumers — mark as published
await db.execute(_MARK_PUBLISHED_SQL, {"id": str(event_id)})
published_count += 1
logger.debug("Outbox event %s already processed, marking as published", event_id)
continue
results = await event_bus.publish_with_results(event_name, payload_dict)
# Check if any handlers were registered at all
@@ -190,13 +202,17 @@ async def process_outbox_batch(
if handler_count == 0:
# No handlers registered — mark as 'no_handlers' not 'published'
# This prevents events from silently disappearing
await db.execute(
text("UPDATE event_outbox SET status = 'no_handlers', published_at = now() WHERE id = :id"),
{"id": str(event_id)},
)
logger.warning("Outbox event %s (%s) had no handlers registered", event_id, event_name)
else:
# Record in consumer_inbox for idempotency (P1.5 fix)
await db.execute(
text("INSERT INTO consumer_inbox (event_id, consumer_name, status, processed_at) VALUES (:eid, :name, 'processed', now()) ON CONFLICT DO NOTHING"),
{"eid": str(event_id), "name": event_name},
)
await db.execute(_MARK_PUBLISHED_SQL, {"id": str(event_id)})
published_count += 1
except Exception as exc: