Skip to content

Add implementing-crash-safe-work-queues skill (application-development) - #23

Open
Dhruvjain35 wants to merge 1 commit into
cockroachlabs:mainfrom
Dhruvjain35:add-skill/application-development/implementing-crash-safe-work-queues
Open

Dhruvjain35 wants to merge 1 commit into
cockroachlabs:mainfrom
Dhruvjain35:add-skill/application-development/implementing-crash-safe-work-queues

Conversation

@Dhruvjain35

Copy link
Copy Markdown

What does this PR do?

Adds implementing-crash-safe-work-queues to application development: the schema and protocol decisions that let a work queue on CockroachDB survive workers being SIGKILLed mid-operation without duplicating external side effects — and without becoming the queueing hotspot the docs warn about. It treats those as the same problem, because the usual fix for one makes the other worse.

Twelve steps, each a decision with its reasoning:

  • Claiming work — one statement: a candidate CTE plus a compare-and-swap on a per-row lease_epoch, so two workers that select the same row cannot both win. SELECT ... FOR UPDATE SKIP LOCKED is treated as an optimization on top of the CAS, not a replacement for it — it is advisory within a transaction and says nothing about a worker that is already gone.
  • Keeping the queue off the hot path — a partial claim index on non-terminal states, so completed rows leave the index and it tracks backlog depth rather than table size; state transitions instead of DELETE, so tombstones never accumulate in front of the next scan; and an explicit computed shard column prefixing the index rather than USING HASH, so workers can be assigned shard subsets by a stable application-facing name.
  • Lease expiry — the lease is liveness, the fencing token is correctness; a paused worker is not a stopped worker. Folding lease expiry into the same available_at column the claim predicate already reads also removes the reaper process, which is itself a common second hotspot.
  • Idempotency keys as GENERATED STORED columns — derived only from immutable columns, so a worker recovering from a crash computes the same key the dead one used and there is no code path that can supply a different one.
  • A recovery table with a defined answer per crash window, and an explicit statement that this is effectively-once, not exactly-once.

references/validation-queries.md carries one assertion per property — plan shape, index size against backlog rather than table size, the CAS rejecting a second claimer, the fence rejecting a zombie write, reconciliation against the external ledger. Every property here degrades silently: the rows still come back correct, just from the wrong plan.

Related Issue

No proposal issue. The skill was already written when I read CONTRIBUTING's proposal step, and opening one retroactively seemed like more noise than a PR you can read. Happy to file one if you would rather have the process in order.

Type of Change

  • New skill
  • Skill update/improvement
  • Documentation update
  • Infrastructure/tooling change
  • Bug fix

Skill Compliance Checklist

  • SKILL.md includes required frontmatter fields (name, description)
  • Skill name follows naming conventions (lowercase, hyphens, gerund form preferred)
  • Skill name matches directory name exactly
  • Description is specific and includes "when to use" trigger keywords
  • Description is max 1024 characters (850)
  • Skill is under 500 lines (390) and uses references/ for detailed content
  • References official CockroachDB documentation (not duplicate content)
  • Includes safety guardrails for risky operations (if applicable)
  • Tested with at least one AI agent (manual validation) — see Testing below
  • No time-sensitive information (version numbers, dates, "currently")
  • Directory structure follows specification (only scripts/, references/, assets/ subdirs)
  • No reserved words in skill name ("anthropic", "claude")
  • Local validation passes: python scripts/validate-spec.py skills/

Documentation Updates

  • README.md — not needed; it lists domains, not individual skills
  • Skill SKILL.md files

Testing

Manual testing:

  • Tested with AI agent — the skill was written from a working implementation rather than validated as a loadable skill, so I have not run a discovery test against a skill-loading agent. Flagging it rather than checking the box.
  • Validated technical accuracy against CockroachDB docs
  • Tested the SQL and the validation queries — the pattern is implemented and crash-tested in the reference implementation linked below, including the plan assertions in references/validation-queries.md

Automated testing:

  • Local validation passes. python scripts/validate-spec.py skills/cockroachdb-application-development/implementing-crash-safe-work-queues/ --strict reports zero errors and zero warnings, including the gerund-form heuristic.
  • CI validation will run automatically on this PR

Additional Context

The pattern comes from AXIOM, a hackathon project — an agent execution layer on CockroachDB with a test per crash window and a harness that SIGKILLs workers mid-refund and reconciles against the provider's ledger afterwards. It is not deployed in production anywhere; the skill is written as general guidance and the implementation is cited once, in References, as something to read rather than something to trust.

Reviewer Notes

Overlap with #22. That PR proposes designing-durable-agent-execution in this same domain, and the two share three ideas: intent committed before the effect, deterministic idempotency keys, and epoch fencing. They differ in what they are about. That one is a per-run step ledger for an agent; this one is the queue table itself, so most of it — partial index shape, tombstones at the queue head, shard prefixing, claim contention, STORING for an index-only claim, eliminating the reaper — is material it does not cover. The two also disagree on one point worth resolving either way: it says exactly-once, this one argues that no system calling an API it does not control can promise that, and says effectively-once. Better you hear about the overlap from me than find it. Happy to narrow scope, cross-reference, merge the two, or drop this if you would rather have one skill in this space.

The scope boundary against designing-application-transactions is stated in the skill itself: retry loops, backoff, and connection pooling are that skill's job, and this one links to it rather than restating it.


By submitting this PR, I confirm:

Adds an application-development skill covering the schema and protocol
decisions that make a work queue on CockroachDB survive worker crashes
without duplicating external side effects, while avoiding the queueing
hotspot the docs warn about: a partial claim index on non-terminal
states, an explicit shard column prefixing that index, state transitions
instead of DELETE, a compare-and-swap on a per-row lease epoch, a fencing
token re-checked on every write, and a GENERATED STORED idempotency key.

Includes references/validation-queries.md with plan and behavior
assertions for each property, since every one of them degrades silently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dhruvjain35 pushed a commit to Dhruvjain35/axiom that referenced this pull request Aug 14, 2026
Four things, and the second one is the reason the others matter.

A PUBLIC AWS FRONT DOOR
The Lambda Function URL has 403'd anonymous callers at the account level since day one,
and every judge-facing document said "no public AWS URL" because of it. API Gateway is a
different service and the restriction does not apply:

  https://nq0i2ob395.execute-api.us-east-2.amazonaws.com   uptime_check 6/6

A Function URL needs lambda:InvokeFunctionUrl for an ANONYMOUS principal, evaluated by
the Function URL front end — that is what the account withholds. API Gateway needs
lambda:InvokeFunction for the NAMED principal apigateway.amazonaws.com, evaluated by the
Lambda control plane, and it is honored. Both doors are live on the same function right
now, which turns the README's account-restriction claim from an assertion into a
demonstration: 403 and 200, same function, same moment.

The deployed Lambda was also serving an Aug 11 build — 40,945 bytes of api.py against
79,657 in the repo — so the two public URLs were running different versions of the
software. Rebuilt and redeployed; both now report identically.

BEDROCK IS RULED OUT, WITH THE QUOTA OUTPUT TO SHOW WHY
The docs said "no model is enabled on this account". That was wrong. Both models are
enabled and both answer. The blocker is quota:

  On-demand requests/min · Titan Text Embeddings V2   0.0
  On-demand tokens/min   · Titan Text Embeddings V2   0.0
  quota L-26C560CE · Adjustable = FALSE · identical in us-east-1/2 and us-west-2
  sustained probe: 0 of 10 calls in 87.4s, all ThrottlingException

Isolated calls DO succeed — a burst allowance — which is precisely why a one-off probe
looks like proof and is not. I built the whole Bedrock integration on two such probes
before measuring properly. Batch inference is available but wants >=100 records per job
and the real corpus is 10 seed texts; padding it to clear the minimum would buy a
checkbox by embedding meaningless strings, so it was not done. AWS now reads 2/5 in use
— Lambda and API Gateway — and the Bedrock entry carries the numbers instead of a hedge.

A TABLE THAT WAS LYING ABOUT ITSELF
axiom_memory.embedding_model was NOT NULL DEFAULT 'amazon.titan-embed-text-v2:0' and no
insert path ever set it, so every row claimed a Titan embedding while holding a blake2b
sketch or a sine test fixture. Nothing computed a wrong answer — both sides of every
cosine comparison were the same embedder — but a table that misdescribes its own contents
is the exact failure this project argues against, and it becomes a real one the moment
two spaces coexist.

Rows were reclassified BY MEASUREMENT, not by assumption: the offline sketch reproduces
exactly from its own text (cos > 0.99999), the fixture reproduces sin(r*0.7 + d*0.013) to
1e-6. Zero rows matched neither, and the relabel refused to run if any had. memory.py now
writes the model explicitly, 005 drops the default so forgetting it is an error rather
than a lie, reembed.py migrates the corpus, and preflight gate 17 reports what is present.

CLAIMS BROUGHT BACK INTO LINE WITH FACTS
CockroachDB reads 3/4, not 4/4: the Agent Skills entry was counted while its PR had never
been opened. It is open now (cockroachlabs/cockroachdb-skills#23, passing their own
validate-spec.py --strict) and stays in_use:false, because this file's rule is that in_use
means part of the running deployed system today.

/api/demo/reset stops being an open TODO and becomes a stated decision: it stays ungated
because Mission Control's buttons send no token, so gating it takes RESET and RUN MISSION
away from the judge the demo exists for.

HANDOFF.md §16 supersedes §§1-15 and names the two conclusions above it that were wrong.

208 tests pass. Both URLs green. $0.00/month.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Dhruvjain35 pushed a commit to Dhruvjain35/axiom that referenced this pull request Aug 16, 2026
An audit of docs/SUBMISSION.md against the live system found eleven false statements, six
stale ones, and — the expensive category — six places where the entry undersold work that
was already done.

THE FALSE ONES GAVE AWAY CREDIT
  - "no PR opened" for the Agent Skills contribution. It is open:
    cockroachlabs/cockroachdb-skills#23, passing their own validate-spec.py --strict.
  - "No CI." CI stands up a real CockroachDB per push, applies five migrations in order,
    runs the suite, then runs the chaos demo under real SIGKILLs, then asserts the vector
    index is still the chosen plan. Listing that as undone forfeits it.
  - Stripe filed under "what's next". It shipped, it is the strongest artefact in the
    entry, and a judge can check it without a Stripe account.
  - "178 passed", in four places and in README four more. It is 260, and the fact that
    they pass with AWS_* unset — hermetic, no credentials, no network — is itself worth
    saying.
  - Month-to-date cost off by three orders of magnitude. The true figure is better copy:
    $0.12, of which $0.12 is Cost Explorer API calls made while checking the bill. The
    product itself has cost $0.0002 in fifteen days.
  - X-Ray described as "active tracing" over four boundaries. It is three subsegments, and
    active on the worker only — the API is deliberately PassThrough, because an Active API
    behind a polling browser tab costs ~$1.73/month per open tab, over the whole budget on
    one tab.

THE PRIMARY URL WAS NOT IN THE DOCUMENT
axiom-one-sage.vercel.app appeared nowhere as a URL; the form instructed judges to the AWS
gateway only. Both are now in a §0 table above everything else, with the Stripe receipt
link and the repo, so a judge who reads nothing else can still check the central claim.

NEW §7b — the five judging criteria, answered directly
Each answer names the command, file or URL that settles it rather than asking to be
believed. Agentic memory design gets the experiment (same receipt, same policy, only the
memory changes, and the verdict moves). Technical implementation gets the containment on
the MCP server, which is what "correctly and safely" is actually asking. Real-world impact
gets $600 vs $300 and Stripe's own words. Production readiness gets W1-W7, the X-Ray trace
id, and 1.33x latency at 3,334x work. Creativity gets the two ideas the entry is built on.

§9 was a video shot list — instructions to ourselves for a video that now exists. Replaced
with what the video shows. §8 is now what the SUBMITTER still has to do.

Every figure re-verified against measurements.json and the live endpoints. "883 ms" for the
memory experiment is now stated as what the endpoint reports run to run — consecutive live
calls returned 883, 888 and 970, and quoting a fixed number would be the exact
over-precision this document argues against.

260 passed, 3 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant