Repository navigation
fix(admin): show a crashed art build as interrupted at once - #75
Merged
Merged
Conversation
Issue #73. A running MTG::ArtBuild whose job the queue has failed, or no longer holds, is left behind once its heartbeat is 2 minutes old (MTG::ArtBuild::JOB_ENDED_GRACE), as a refresh run is since issue #60. MTG::ArtBuild.start! reads the queue before the builds and closes such a build as interrupted, so the new build runs instead of being skipped as already running. The 10-minute stale rule and the own-job rule are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73, through MTG::Art::Build#call: the build left running by a job the queue has failed is closed and the new build runs; one whose job a worker still holds makes the new build a skip. Seen failing with MTG::ArtBuild#left_behind? cut back to the stale rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73. MTG::Art::Operation#state judged a running build by its heartbeat alone, so after a crash the art index read "Building." with "Build art index" disabled until the build went stale, while its job already sat under Failed. It now asks MTG::ArtBuild#left_behind?, with the queue read before the build: the build is interrupted once it has gone 2 minutes without a heartbeat and the queue has failed its job or no longer holds it. A build whose job is still in the queue, or that beat within 2 minutes, stays "Building.". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73. MTG::Art.status_line read "building" for any running build that wasn't stale. It now reads the queue, then the build, and asks MTG::ArtBuild#left_behind?, as the art index's panel does: a build whose job the queue has failed, or no longer holds, is interrupted once it has gone 2 minutes without a heartbeat. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73. With the button usable again after a crash, pressing "Build art index" left the section reading "Interrupted. Build it again to carry on from where it stopped." with the button disabled until the new job started and closed the old build. A build nothing is working on now reads "Queued." while a build job waits to start (spec 015 AC-4.3), as the refresh does since 92631bb. A build whose heartbeat stopped while a worker still holds its job stays interrupted, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73. Spec 015 1.2.3: the glossary's Interrupted entry, a new AC-4.10 and two Error Scenarios rows say that an art build whose job the queue has failed, or no longer holds, is interrupted once its heartbeat is 2 minutes old, that a build queued behind it shows as queued, and what remains when a live build's batch takes longer than that. CLAUDE.md names MTG::ArtBuild#left_behind? and its readers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…minutes Issue #73. Spec 011 1.1.4: AC-3.2, AC-3.8, AC-3.11 and the crash row of Error Scenarios stated the staleness cutoff as the only way a crashed build stops blocking the next one and reads as Interrupted. They now name the 2-minute rule for a build whose job the queue has failed or no longer holds, and point at spec 015 AC-4.10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73. A comment on MTG::ArtBuild::JOB_ENDED_GRACE: the build beats once per batch of 50 artworks, so a batch with several hung image requests outlasts the grace. Spec 015's Error Scenarios say what follows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73, review follow-up. The build beat only after each batch of 50 artworks, and a batch slowed by rate limits, server errors or hung requests outlasts MTG::ArtBuild::JOB_ENDED_GRACE: a live build whose job the queue had failed, or that ran outside the queue, then read as interrupted, and a second build closed it and ran beside it. MTG::Art::Build now also beats after an image when its last beat is MTG::Art::Build::BEAT_EVERY (30 seconds) old. What remains is one image that by itself takes more than 90 seconds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73, review follow-up. The issue's own scenario is a build whose job sits under Failed, and the section didn't point there: MTG::Art::Operation#failed_job? was true only for a failed build. It is now also true for an interrupted build whose own job is in the queue's failed list, as Catalog::RefreshOperation#failed_job? is for a run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… 2 minutes Issue #73, review follow-up. The grace compared with <= while the stale rule beside it, and the documents, say "older than": a heartbeat exactly 2 minutes old now still counts, as one exactly 10 minutes old does. Also adds the cases the review found missing in MTG::ArtBuild's spec: both boundaries, a build whose job is scheduled to run again, one whose job never was in the queue and beat within 2 minutes, one that recorded no job, and start! leaving alone a build that started after it read the queue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…page Issue #73, review follow-up: the own-job path at request level. The retried job waits in the queue, so the build reads "Building." again with no link to the Failed list, and the job closes its own build when it starts. The behaviour was already there; the example passed when written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #73, review follow-up. Spec 015: AC-4.10 names the link to the Failed list, the changelog row and the residual row state the 30-second heartbeat and the one-image case that remains, and "2 minutes old" becomes "older than 2 minutes", as the code compares. Spec 011's crash row and CLAUDE.md likewise. MTG::Art::Operation's header says where the page and the art line of catalog:status differ (a queued build) instead of saying they agree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Ruling (maintainer, 2026-10-13): keep |
This was referenced Oct 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After an art index build's worker crashes,
/admin/catalognow reads "Interrupted…" with "Build art index" enabled and a link to the failed job, instead of "Building." with the button disabled for up to 10 minutes. A build started then runs instead of being skipped as "already running".Closes #73
Cause
Three places judged a running
MTG::ArtBuildby its heartbeat alone and never asked the queue:MTG::Art::Operation#state,MTG::Art.status_lineandMTG::ArtBuild.start!. This is issue #60's flaw in the art operation's own code; PR #69 fixed the refresh and left this alone.What changed
MTG::ArtBuild#left_behind?(queue): a running build is left behind when it is stale (10 minutes, as before), or when its heartbeat is older than 2 minutes and the queue has failed its job or no longer holds it. The page, the art line ofcatalog:statusandstart!all ask it, each reading the queue before the builds, as the refresh does.MTG::ArtBuild::JOB_ENDED_GRACE(2 minutes) is the build's constant, not the refresh's: the right length depends on how often each job records progress. No core file changed.MTG::Art::Build::BEAT_EVERY, 30 seconds), as well as per batch of 50. The review showed with a probe that a live build quiet for over 2 minutes inside one batch could be closed by a second build, which then ran beside it and wrote the same index file. With the extra beat that needs one image to take over 90 seconds by itself.c7854ba, mirroring the refresh). Without it, pressing the re-enabled button leaves "Interrupted. Build it again…" with a disabled button until a worker picks the job up. Revert that one commit for strict scope.start!is now<10 minutes, the same asstale?.CLAUDE.mdmatch. No view, CSS, copy or migration change.Verification
bin/cion377fb0a: passed. RSpec 1305 examples, 0 failures, 1 pending (the art agreement spec, unrelated).stale?, which reproduced the issue exactly.Known limits and follow-ups
perform_now, it reads interrupted until its next heartbeat, and a build started then runs beside it. Recorded in spec 015's Error Scenarios. On this branch aRetry-Afterwait is uncapped; Scryfall client sleeps for Retry-After with no upper bound #74's fix caps it, and its PR is stacked on this one.catalog:statusdiffer only while a build job waits in the queue: the page says "Queued.", the status line still describes the latest build.docs/specs/011-card-scanner-art-matching/data-model.mdstill says the heartbeat is updated after every batch; true but incomplete.docs/roadmap.mddoesn't list Art index reads "Building." after a crashed build #73 yet.🤖 Generated with Claude Code