Skip to content

fix: announce agreement events promptly and pause on outages#670

Merged
cmwhited merged 2 commits into
chris.whited/feat-producer/wire-into-dipper-svcfrom
mb9/emit-agreement-events-without-sweep-delay
Jul 14, 2026
Merged

fix: announce agreement events promptly and pause on outages#670
cmwhited merged 2 commits into
chris.whited/feat-producer/wire-into-dipper-svcfrom
mb9/emit-agreement-events-without-sweep-delay

Conversation

@MoonBoi9001

@MoonBoi9001 MoonBoi9001 commented Jul 14, 2026

Copy link
Copy Markdown
Member

The chain listener polls the subgraph for agreement state and announces each accepted, terminated or expired agreement on a Kafka topic that downstream consumers watch. This PR makes those announcements go out on every poll instead of every 60th, and adds a short cooldown so a Kafka outage cannot stall the poller.

Until now the 3 announcements were emitted only by a recovery sweep that runs every 60th poll. At the active 30-second poll rate an announcement could trail its state change by up to 30 minutes; worse, cancelling the last live agreement drops the listener to its 5-minute idle poll rate, parking that final termination announcement for up to 5 hours. Running the sweeps every poll closes that gap: each per-event query is backed by a partial index, so an empty sweep is cheap.

Sweeping every poll makes a broker outage more expensive, though. Each sweep sends synchronously with a 30-second timeout, so a hung broker would block all 3 sweeps for up to 90 seconds on every poll and fill the logs with warnings. After a failed send the listener now pauses the event sweeps, backing off from one poll interval (30 seconds) up to 5 minutes and retrying, then resumes once a send succeeds. The cancellation recovery sweeps, which do not send Kafka events, and the healthy path where the broker is up are both unchanged.

A separate review finding about diagnostic events being dropped when the in-memory send queue fills is already handled on this base branch: the queue capacity is configurable (default 1,024) and every drop is counted and logged. No change was needed for it here.

A recovery sweep running only every 60th poll was the sole emitter of the accepted,
terminated and expired announcements, delaying each by 30 minutes while polling fast and
up to 5 hours once the last live agreement was cancelled. Run those three every poll.
@MoonBoi9001 MoonBoi9001 added the agreement-events Kafka producer for agreement lifecycle events (Studio integration) label Jul 14, 2026
@MoonBoi9001 MoonBoi9001 changed the title fix: announce agreement lifecycle events without a sweep delay fix: announce agreement events promptly and pause on outages Jul 14, 2026
Now that the accepted, terminated and expired announcements sweep every poll, a hung Kafka
broker made each of the 3 sweeps block on its 30-second send, stalling chain polling every
poll. After a failed send the sweeps now back off from 30 seconds up to 300 before retrying.
@MoonBoi9001
MoonBoi9001 force-pushed the mb9/emit-agreement-events-without-sweep-delay branch from 5c51ac2 to 6bacf8d Compare July 14, 2026 05:57
@MoonBoi9001
MoonBoi9001 requested a review from cmwhited July 14, 2026 06:07

@cmwhited cmwhited left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate this 🙏

@cmwhited
cmwhited merged commit 040845f into chris.whited/feat-producer/wire-into-dipper-svc Jul 14, 2026
18 of 19 checks passed
@cmwhited
cmwhited deleted the mb9/emit-agreement-events-without-sweep-delay branch July 14, 2026 18:27
cmwhited added a commit that referenced this pull request Jul 14, 2026
…emitter in callsites (#656)

* feat(events producer): implement subgraph indexing agreements events emitter in callsites

* feat(events producer): only emit n_indexer_unavailable once

* fix: correct expiry timestamps and a duplicated shortfall event (#658)

* fix(reassess): send shortfall event after the chain-time read

The "not enough indexers" event was sent before the step that reads chain time to
stamp deadlines. In local runs that read can fail and retry the whole job, resending
the event each round; sending it after the read makes a retried round emit it once.

* fix(expiration): report proposal time from the deadline clock

The expiry event mixed clocks: "proposed at" came from wall time, "expired at" from
chain time, so with local time controls on, expiry could look earlier than the proposal.
Agreements now stamp proposal time in the deadline's clock; old rows fall back to created_at.

* feat(events producer): PR review. hardening. atomic retries. error and app shutdown handling

* fix: announce agreement events promptly and pause on outages (#670)

* fix(listener): announce agreement events on every chain poll

A recovery sweep running only every 60th poll was the sole emitter of the accepted,
terminated and expired announcements, delaying each by 30 minutes while polling fast and
up to 5 hours once the last live agreement was cancelled. Run those three every poll.

* fix(listener): pause event sweeps briefly after a Kafka send failure

Now that the accepted, terminated and expired announcements sweep every poll, a hung Kafka
broker made each of the 3 sweeps block on its 30-second send, stalling chain polling every
poll. After a failed send the sweeps now back off from 30 seconds up to 300 before retrying.

---------

Co-authored-by: MoonBoi9001 <67825802+MoonBoi9001@users.noreply.github.com>
cmwhited added a commit that referenced this pull request Jul 14, 2026
…end events to kafka (#649)

* feat(events producer): subgraph indexing agreement event emitter to send events to kafka

* feat(events producer): cleanup. add simple tests to emitter

* feat(events producer): implement subgraph indexing agreements events emitter in callsites (#656)

* feat(events producer): implement subgraph indexing agreements events emitter in callsites

* feat(events producer): only emit n_indexer_unavailable once

* fix: correct expiry timestamps and a duplicated shortfall event (#658)

* fix(reassess): send shortfall event after the chain-time read

The "not enough indexers" event was sent before the step that reads chain time to
stamp deadlines. In local runs that read can fail and retry the whole job, resending
the event each round; sending it after the read makes a retried round emit it once.

* fix(expiration): report proposal time from the deadline clock

The expiry event mixed clocks: "proposed at" came from wall time, "expired at" from
chain time, so with local time controls on, expiry could look earlier than the proposal.
Agreements now stamp proposal time in the deadline's clock; old rows fall back to created_at.

* feat(events producer): PR review. hardening. atomic retries. error and app shutdown handling

* fix: announce agreement events promptly and pause on outages (#670)

* fix(listener): announce agreement events on every chain poll

A recovery sweep running only every 60th poll was the sole emitter of the accepted,
terminated and expired announcements, delaying each by 30 minutes while polling fast and
up to 5 hours once the last live agreement was cancelled. Run those three every poll.

* fix(listener): pause event sweeps briefly after a Kafka send failure

Now that the accepted, terminated and expired announcements sweep every poll, a hung Kafka
broker made each of the 3 sweeps block on its 30-second send, stalling chain polling every
poll. After a failed send the sweeps now back off from 30 seconds up to 300 before retrying.

---------

Co-authored-by: MoonBoi9001 <67825802+MoonBoi9001@users.noreply.github.com>

---------

Co-authored-by: MoonBoi9001 <67825802+MoonBoi9001@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agreement-events Kafka producer for agreement lifecycle events (Studio integration)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants