Skip to content

Build1 publisher3 min readPublished

A webhook that only verifies, claims and acks is the cheapest way to make delayed work safe

A dev.to writeup on marketplace cleanup keeps the HTTP request out of the delete path and pushes retries into a bounded worker. The duplicate-delivery race is the test case, not an edge case.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying A webhook that only verifies, claims and acks is the cheapest way to make delayed work safe
Generated illustration

What happened

  • The dev.to post argues a public HTTPS queue push webhook subscriber in Node.js should verify the signature on the raw request, persist a unique cleanup command, and ack only after that durable write, with a bounded worker owning retries.
  • The request should never wait for the marketplace cleanup itself.
  • A marketplace can tolerate a cleanup running a few minutes late, but cannot easily tolerate deleting a listing twice, charging a seller twice, or turning one delivery retry into two irreversible side effects.
  • The design is framed around one bounded scenario: an expired marketplace listing is placed on a delayed queue, a push delivery reaches a public endpoint, and a worker removes stale search and reservation data.
  • The endpoint's job is to accept responsibility for the command; it is not the worker, and it is not a second scheduler hiding inside an HTTP request.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

A dev.to post credited to Ethan Brooks sets a narrow contract for a public HTTPS endpoint that receives delayed queue pushes: verify the signature over the raw request, persist a unique cleanup command, acknowledge only after that durable write, and let a bounded worker own retries [1]. The consequential part is what it forbids, which is the request waiting on the marketplace cleanup itself [2].

The justification is asymmetry of damage. A marketplace can tolerate a cleanup that runs a few minutes late; it cannot easily tolerate deleting a listing twice, charging a seller twice, or turning one delivery retry into two irreversible side effects [3]. The scenario is deliberately bounded: an expired listing goes onto a delayed queue, a push delivery arrives at a public endpoint, and a worker removes stale search and reservation data [4]. In that shape the endpoint's only job is to accept responsibility for the command. It is not the worker, and it is not a second scheduler hiding inside an HTTP request [5].

Order of operations carries the design. Verify against the exact bytes received, and parse the payload after authentication rather than before, because re-serialization can change the bytes an HMAC covers [6]. Check the delivery identifier and the message type too, since an authenticated message with an unexpected schema is still not a valid cleanup command [7]. Then claim the delivery in durable shared state, with a uniqueness constraint on the delivery ID or on a business key such as listing_id plus cleanup generation when the producer may legitimately issue a new delivery for the same listing [8]. A process-local map does not qualify: it disappears on restart and says nothing to the next instance behind the load balancer [9]. Only after that write does the handler return the queue's success acknowledgement [10]. If the database is unavailable, the honest reply is a non-success response that allows redelivery, because silently acknowledging after an in-memory write creates loss a dashboard may never reveal [11].

The sample handler is written in Go with an application-owned HMAC contract, so the sequence is visible without pretending every queue uses the same header names, and the author notes a Node.js implementation would follow the same order [12]. Mechanically it rejects non-POST methods with 405, reads the body through a reader capped at 256*1024 bytes, hex-decodes an X-App-Signature header, compares it to an HMAC-SHA256 of the body using a constant-time equality check and returns 401 on mismatch, returns 400 when X-Delivery-ID is absent, and returns 503 when the claim store errors [13]. That cap is 256 KiB [14]. StoreClaim itself must sit on a shared transactional store and return false for a delivery already claimed [15].

The test case named in the post is the one most teams defer: two copies of the endpoint receive the same listing-4821:expiry-7 command milliseconds apart, both verify the signature, one wins the durable uniqueness check, and the loser sees the existing claim and acknowledges without creating a second worker job [16]. The author would run that while one instance is draining and while the database transaction sits near its timeout [17].

What to watch is state modelling, not throughput. Three outcomes must be distinguishable: insert committed but response lost, where the redelivery must be harmless [18]; insert not committed, where the retry must be able to establish ownership [19]; and a worker that lost its lease, where a replacement must resume from a safe checkpoint or repeat an operation whose key means the same thing [20]. Collapsing those into a boolean processed flag makes incident analysis speculative [21], which is the cost you pay later for the schema you skip now.

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories