Document stores: *Send now* re-claims a copy the scheduler is already sending, so it is put twice #509
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#509
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, reading the claim that #221 added to store copies, and confirmed by runningclaimagainst the snapshot.Checked again on 2026-10-01 against
mainat0a5cad587: still present.claim()is a conditional update against thenext_attempt_atthe caller read, and a claim movesnext_attempt_ata quarter of an hour ahead. The scheduler never sees a claimed copy again, because it only reads copies that are due. Send now reads every copy not yet sent, whatever itsnext_attempt_at. If it reads after the scheduler has claimed a copy, it reads the lease value, its own claim matches that value, and it sends the same copy again while the firstputis still under way.documents/archiving.py:192-208,claim;documents/archiving.py:224-242,send_now, whose query isDocumentCopy.objects.filter(**_lookup(document)).exclude(status=CopyStatus.SENT); the caller isdocuments/views.py:678-728,SendCopiesNowView.send_nowreads the copy with its leasednext_attempt_at,claimsucceeds against that value, andsend_copycallsplugin.puta second time. Run against the snapshot: after a scheduler-stylepending_copies()andclaim(), a fresh read followed byclaim()returnedTrue, and so did a third. Only a caller holding the value read before the first claim loses. The same holds for two Send now requests for one document from two tabs, or with scripts off; the once-only submit instatic/js/app.js(the "a form is sent once" block) stops a double click in one page.claim's docstring and the wiki still say nothing is ever sent twice.claimed_untilcolumn (or a sending status with a lease timestamp); haveclaimupdate only whereclaimed_until IS NULL OR claimed_until < now, in the same statement; clear it insend_copywhen the outcome is recorded.send_nowcan then go on overriding the retry wait of a failed copy without ever taking a live lease, and a copy whose worker died still comes back when the lease runs out.Done when
tests/test_stores.pyclaims a copy as the scheduler does, then callssend_nowfor its document with a fake store, and asserts the store'sputwas called once in total andsend_nowreported nothing sent.Related to #221, which added the claim and was closed as covering this overlap.