diff --git a/Gemfile.lock b/Gemfile.lock index 217223a1..8b646f62 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -362,7 +362,7 @@ GEM activejob (>= 7.2) activerecord (>= 7.2) railties (>= 7.2) - solid_queue (1.7.0) + solid_queue (1.7.2) activejob (>= 7.1) activerecord (>= 7.1) concurrent-ruby (>= 1.3.1) @@ -599,7 +599,7 @@ CHECKSUMS simpleidn (0.3.0) sha256=12ca730bed2f3db04d11e9bfd1bca3e11fb37f55b21eb2e9793fb5814bf54d03 solid_cable (4.1.0) sha256=828e3d509207b82b4f05f4e9c85f696994710679b52d511aa7f97ebd212d3226 solid_cache (1.0.10) sha256=bc05a2fb3ac78a6f43cbb5946679cf9db67dd30d22939ededc385cb93e120d41 - solid_queue (1.7.0) sha256=6566b70b801d1c317c81bba7bcdd5677c019afac584a30374b4164002ca356d3 + solid_queue (1.7.2) sha256=a22685e1d2ee14ce7b4e5d4592c9d8e837951884c51555609dee58679ed03325 sqlite3 (2.10.2-aarch64-linux-gnu) sha256=e9aea2c2b3476fc875dd8a89313a9a2862818519c0186bfb5b56d6f57bb08d98 sqlite3 (2.10.2-aarch64-linux-musl) sha256=4986fc40cdf21342362b72a941df28e95cfe0e644f3ad2532d948b157c39dbee sqlite3 (2.10.2-arm-linux-gnu) sha256=762f609ef891463226b472d3df66aea84d5466ff4376d3ccf4a059718c4ce9c9 diff --git a/docs/architecture/catalog-operations.md b/docs/architecture/catalog-operations.md index e610dde4..979bfefa 100644 --- a/docs/architecture/catalog-operations.md +++ b/docs/architecture/catalog-operations.md @@ -53,7 +53,7 @@ How the catalog changes, and how admins start, watch and recover that work: the - **A retry or discard from the jobs pages changes no run** by itself; a retried job changes runs only when it runs (spec 015 AC-6.11). - **Pages poll only while work is in flight**, with the `poll` controller, re-rendering from recorded state; jobs never broadcast or render (spec 015 FR-4; ADR 0015). - **The jobs pages read Solid Queue's own tables** and retry or discard only failed jobs, through Solid Queue's own operations; a request names only a job's id, a catalog type and an operation's key, each looked up among what exists (spec 015 FR-5, FR-7; ADR 0014). -- **The catalog page moves one scheduled job, through the queue's own operations.** "Retry now" names only a type and an operation key, takes the job from the operation's own latest failed run, runs nothing in the request and writes no run record; it is admin only like the rest of the page (spec 055 decision 4, FR-1; ADR 0014). +- **The catalog page moves one scheduled job, through the queue's own operations.** "Retry now" names only a type and an operation key, takes the job from the operation's own latest failed run, runs nothing in the request and writes no run record; it is admin only like the rest of the page (spec 055 decision 4, FR-1; ADR 0014). Moving the job keeps its Active Job id and its Active Job arguments as they were (spec 055 FR-2); the queue's own bookkeeping in the stored row may change, as Solid Queue 1.7.2 records there which concurrency semaphore the dispatched job took its slot from (maintainer ruling on [#283](https://github.com/plainprogrammer/Collector/issues/283)). - **A failure is shown as a plain sentence, never an error's class name.** A failed run or build stores `": "`; `Catalog::FailureReason` derives the sentence from it each time it is shown, so runs that failed before #84 read the same way. The core words `Catalog::Sources`' errors and a busy database, a source words its own errors through `.failure_reasons`, and anything else reads "An unexpected error stopped it."; a message that isn't an error's (`interrupted`) is shown as a sentence. The panel keeps the stored text as a "Technical detail" fact; `catalog:status` and the log print the stored text unchanged (#84). `MTG::Scryfall::Source` words a missing ImageMagick this way (#84). - **Admins only.** Every page and action of `/admin/catalog` and `/admin/jobs` answers 404 to a member (nothing is queued, retried or discarded) and sends a visitor to sign in (spec 015 FR-7, AC-7.1, AC-7.2). @@ -216,7 +216,7 @@ Filter chips Failed (the default), Running, Queued and Scheduled, each with its - [Spec 055](../specs/055-rate-limit-retry-now/spec.md): all. - [Spec 058](../specs/058-mtg-mana-value/spec.md) decision 3 (`#reapply?`'s second reason). - ADRs [0014](../adr/0014-hand-built-admin-jobs-console.md), [0015](../adr/0015-admin-progress-by-polling.md), [0018](../adr/0018-collectible-agnostic-catalog-core.md). -- Issues [#60](https://github.com/plainprogrammer/Collector/issues/60), [#61](https://github.com/plainprogrammer/Collector/issues/61), [#73](https://github.com/plainprogrammer/Collector/issues/73), [#74](https://github.com/plainprogrammer/Collector/issues/74), [#78](https://github.com/plainprogrammer/Collector/issues/78), [#79](https://github.com/plainprogrammer/Collector/issues/79), [#80](https://github.com/plainprogrammer/Collector/issues/80), [#81](https://github.com/plainprogrammer/Collector/issues/81), [#84](https://github.com/plainprogrammer/Collector/issues/84), [#86](https://github.com/plainprogrammer/Collector/issues/86), [#111](https://github.com/plainprogrammer/Collector/issues/111), [#122](https://github.com/plainprogrammer/Collector/issues/122), [#176](https://github.com/plainprogrammer/Collector/issues/176), [#77](https://github.com/plainprogrammer/Collector/issues/77) (discarding a waiting retry stays out of scope); open: [#41](https://github.com/plainprogrammer/Collector/issues/41). +- Issues [#60](https://github.com/plainprogrammer/Collector/issues/60), [#61](https://github.com/plainprogrammer/Collector/issues/61), [#73](https://github.com/plainprogrammer/Collector/issues/73), [#74](https://github.com/plainprogrammer/Collector/issues/74), [#78](https://github.com/plainprogrammer/Collector/issues/78), [#79](https://github.com/plainprogrammer/Collector/issues/79), [#80](https://github.com/plainprogrammer/Collector/issues/80), [#81](https://github.com/plainprogrammer/Collector/issues/81), [#84](https://github.com/plainprogrammer/Collector/issues/84), [#86](https://github.com/plainprogrammer/Collector/issues/86), [#111](https://github.com/plainprogrammer/Collector/issues/111), [#122](https://github.com/plainprogrammer/Collector/issues/122), [#176](https://github.com/plainprogrammer/Collector/issues/176), [#77](https://github.com/plainprogrammer/Collector/issues/77) (discarding a waiting retry stays out of scope); open: [#41](https://github.com/plainprogrammer/Collector/issues/41), [#283](https://github.com/plainprogrammer/Collector/issues/283). ## Distillation log diff --git a/spec/models/catalog/operation/queue_spec.rb b/spec/models/catalog/operation/queue_spec.rb index db80b893..b3ca8aa3 100644 --- a/spec/models/catalog/operation/queue_spec.rb +++ b/spec/models/catalog/operation/queue_spec.rb @@ -120,13 +120,18 @@ describe "#run_now (spec 055 FR-2)" do def waiting(wait: 10.minutes) = queue_job(Catalog::RefreshJob, "mtg", "manual", wait:) + # "Its arguments" are the job's Active Job arguments, not the whole stored column: Solid Queue keeps its own + # bookkeeping there, and 1.7.2 adds the semaphore a concurrency-limited job took its slot from when the job + # is dispatched (rails/solid_queue#831). The maintainer's ruling on #283 reads FR-2 this way. it "makes a scheduled job ready, adding no job and leaving its Active Job id and arguments as they were", :aggregate_failures do job = waiting - before = job.slice(:id, :active_job_id, :arguments) + identity = ->(record) { [ record.id, record.active_job_id, record.arguments["job_id"], record.arguments["arguments"] ] } + before = identity.(job) expect { expect(queue.run_now(job.active_job_id)).to be(true) }.not_to change(SolidQueue::Job, :count) - expect(job.reload.slice(:id, :active_job_id, :arguments)).to eq(before) + expect(identity.(job.reload)).to eq(before) + expect(before.last).to eq([ "mtg", "manual" ]) expect(job).to be_ready expect(job.scheduled_execution).to be_nil expect(job.blocked_execution).to be_nil