Skip to content

fix(filler): defer update_atomicmarket_stats_market while the reader is catching up#68

Open
igorls wants to merge 1 commit into
atomicassets:mainfrom
igorls:fix/defer-stats-market-during-catchup
Open

fix(filler): defer update_atomicmarket_stats_market while the reader is catching up#68
igorls wants to merge 1 commit into
atomicassets:mainfrom
igorls:fix/defer-stats-market-during-catchup

Conversation

@igorls

@igorls igorls commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Problem

update_atomicmarket_stats_market() recomputes the whole due backlog in a single unbounded statement. Every other heavy maintenance job — update_atomicmarket_template_prices and the sales-filter drain — is gated on Filler.shouldDeferDrain(), but this one is not.

On a catchup-sized atomicmarket_stats_markets_updates backlog the recompute exceeds the connection statement_timeout and is cancelled (57014) on every 2-minute tick, so market stats never refresh during catchup and the doomed query contends with block-writes (intermittent No blocks processed … Stopping in N seconds).

Observed on a production WAX-mainnet cluster: the job timed out every tick against a ~3.3M-row atomicmarket_stats_markets_updates backlog while the reader was ~1.3M blocks behind head.

Fix

Gate the job on this.filler.shouldDeferDrain(), exactly like its siblings: skip while the reader is catching up; stats refresh on the next tick once the reader is live.

Validation

  • pnpm check-types clean.
  • Verified on the production WAX-mainnet cluster: with the gate, the per-tick 57014s stop and the reader no longer competes with the stats recompute during catchup.

…hes up

update_atomicmarket_stats_market() recomputes the whole due backlog in one
unbounded statement. Every other heavy maintenance job (update_atomicmarket_
template_prices, the sales-filter drain) is gated on Filler.shouldDeferDrain(),
but this one was not — so against a catchup-sized atomicmarket_stats_markets_
updates backlog it busts the connection statement_timeout (57014) on every
2-minute tick and contends with block-writes ("No blocks processed").

Gate it like its siblings: skip while the reader is far behind head; stats
refresh on the next tick once the reader is live.
@igorls
igorls marked this pull request as ready for review June 9, 2026 01:51
Copilot AI review requested due to automatic review settings June 9, 2026 01:51

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a drain-deferral gate to avoid expensive/unbounded stats recomputation queries while the reader is catching up, reducing statement timeouts and write contention during backlog recovery.

Changes:

  • Skip update_atomicmarket_stats_market() execution when shouldDeferDrain() indicates the reader is catching up.
  • Document why the gate exists (statement timeout / contention) and how it aligns with other existing gates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +743 to +752
// Reader-priority gate: skip the stats recompute while the reader is catching up.
// update_atomicmarket_stats_market() processes every due row in
// atomicmarket_stats_markets_updates in a single unbounded statement, so against a
// catchup-sized backlog it busts this connection's statement_timeout on every 2min
// tick (57014) and contends with block-writes. It refreshes on the next tick once the
// reader is live. Mirrors the gate on update_atomicmarket_template_prices below and
// the sales-filter drain above.
if (this.filler.shouldDeferDrain()) {
return;
}

@robrigo robrigo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review (FACINGS) — LGTM.

Verified Filler.shouldDeferDrain() exists and that the sibling heavy jobs (sales-filter drain + update_atomicmarket_template_prices) use the same gate — update_atomicmarket_stats_market was the lone ungated one. Confirmed the same gap exists on feat/atomicassets-v2 (its stats_market job is ungated too), so this is needed there as well; the patch applies cleanly onto v2.

Copilot's note (silent skip is hard to observe during catch-up) is fair but consistent with the existing sibling gates, which are also silent — fine as an optional follow-up (a rate-limited debug log), not a blocker.

robrigo added a commit that referenced this pull request Jun 9, 2026
AtomicAssets v2 (dual ownership/renting, mutable templates, schema media types,
collection author swaps) was originally authored by Fabian Emilius in the WAX-OIG
eosio-contract-api fork; this repo carries it forward as a reconstruction onto 1.7.2.
Record the original authorship and co-attribute it. Also credits @igorls for the v2
catch-up/upgrade-safety fixes (#68/#69/#70).

Co-authored-by: Fabian Emilius <20770096+fabian-emilius@users.noreply.github.com>
Co-authored-by: Igor Lins e Silva <4753812+igorls@users.noreply.github.com>
@igorls

igorls commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Rechecked against current main (head migration 1.7.17): update_atomicmarket_stats_market is still the lone heavy job registered without a shouldDeferDrain() gate in src/filler/handlers/atomicmarket/index.ts — its sibling update_atomicmarket_template_prices is gated, this one isn't — so the gap this closes is still present upstream. GitHub reports the branch MERGEABLE (no conflicts). Ready to merge whenever convenient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants