Provider validation: lease fencing and exactly-once consumption
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 38/100
Línea de trabajo
Start with the Provider trait in src/providers/mod.rs and the lock expiration tests, especially lock_expiration and instance_locking. Read the provider implementation guide at docs/provider-implementation-guide.md to confirm the lease renewal contract, including whether renewal can shorten a lease. Add the listed provider trait tests and verify them on SQLite; acceptance also calls for checking the PostgreSQL provider and measuring test 6's failure rate on its earlier revision.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Why
microsoft/duroxide-pg#44 fixes a provider bug that the validation suite did not catch, microsoft/duroxide-pg#29:
- An orchestration acknowledge committed after another dispatcher had already taken the instance over.
- The messages that acknowledge consumed stayed queued, and the next owner processed them again.
- Replay does not de-duplicate queue messages or external events. So, reproduced end to end with duroxide 0.1.32, one enqueued event ran an activity twice.
The suite already checks some related cases:
- a stale token that is rejected before the acknowledge starts (
lock_expiration::test_lock_expires_after_timeout, which acknowledges an empty turn); - two acknowledges with the same token (
atomicity::test_concurrent_ack_prevention).
It does not check that ownership holds until the acknowledge commits. It also has no positive test for orchestration lock renewal; the worker side has three.
All tests below use only the Provider trait and ProviderFactory::lock_timeout() (written T below). They should pass on the SQLite provider.
Contract changes (src/providers/mod.rs, docs/provider-implementation-guide.md)
ack_orchestration_item: the lock token must still own the instance when the acknowledge commits, not only when it starts. If ownership was lost at any point, the acknowledge fails with a permanent error and commits nothing: no history, no new work, no deleted messages.renew_orchestration_item_lock: once the token no longer owns the instance (after an acknowledge, an abandon or a takeover), renewal fails and changes nothing. It must not lock released messages again or change the new owner's lease.- Decide whether renewal may shorten a lease. The documented pattern is
locked_until = now() + extend_for. Proposed:locked_until = max(locked_until, now() + extend_for). duroxide-pg does this since microsoft/duroxide-pg#44.
Tests to add
| # | Module | Test | Steps | Must hold |
|---|---|---|---|---|
| 1 | lock_expiration |
test_ack_after_takeover_commits_nothing |
Fetch as A (lock T). Sleep past T. Fetch as B. Acknowledge as A with a non-empty history delta and one worker item | A's acknowledge fails. read(instance) has none of A's events, and A's worker item was not enqueued. B's acknowledge succeeds, and no later fetch returns the message |
| 2 | lock_expiration |
test_orchestration_lock_renewal_extends_lock |
Fetch (lock T). Renew for 3T. Sleep 2T | A second fetch returns nothing. An acknowledge with the original token succeeds |
| 3 | lock_expiration |
test_orchestration_renewal_after_takeover_fails |
Fetch as A. Wait for expiry. Fetch as B. Renew as A | The renewal fails. A fetch right after it returns nothing. B's acknowledge succeeds and consumes the message once |
| 4 | lock_expiration |
test_orchestration_renewal_after_release_fails |
(a) Fetch, acknowledge, renew. (b) Fetch, abandon with no delay, renew | Both renewals fail. In (b), a fetch right after the renewal returns the message: renewal did not lock it again |
| 5 | lock_expiration |
test_orchestration_renewal_never_shortens (after contract item 3) |
Fetch (lock T). Renew for 4T. Renew for T. Sleep 2T | A second fetch returns nothing |
| 6 | instance_locking |
test_acknowledged_messages_never_redelivered_under_takeover_race |
N rounds (default 100). Each round: enqueue one QueueMessage. A fetches (lock T) and sleeps until about T, with jitter across rounds. Then A acknowledges a turn that consumes the message, while B polls fetch for up to 2T and acknowledges anything it gets with its own token. After every lock has expired, fetch once more |
Per round, at most one acknowledge that consumed the message succeeds. Once one succeeds, no later fetch returns the message |
Notes:
- Tests 1 to 4 document the contract. A provider that checks the token only at the start of an acknowledge still passes them, because the takeover happens before the call.
- Test 5 fails on duroxide-pg
main(3beba92), whose renewal can shorten a lease. - Test 6 is the one that targets microsoft/duroxide-pg#29. It is timing-based: measure its failure rate on duroxide-pg
3beba92before relying on it. If the window is too narrow to hit reliably, keep it as a soak test with a configurable round count.
Acceptance
- Tests 1 to 4, and test 5 once the contract is decided, pass on SQLite and on duroxide-pg with microsoft/duroxide-pg#44.
- Test 5 fails on duroxide-pg
3beba92. - Test 6 passes on microsoft/duroxide-pg#44, and its failure rate on
3beba92is recorded in the PR. - After the next duroxide release, duroxide-pg registers the new tests in
tests/postgres_provider_test.rs.
Out of scope (these stay in duroxide-pg)
- The clock-skew races, which need a faked caller clock that the trait cannot provide.
- The PostgreSQL lock-order deadlock tests and the deadlock-victim retry.
- The
instance_locks(lock_token)index test.
These are in tests/deadlocks/ and tests/orchestration_*_tests.rs in microsoft/duroxide-pg#44. The TLA+ model in docs/tla/orchestration-leases there states the same properties formally.
Related
- #55: tracking issue.
- #58: the fallback abandon is dropped without
.await. - #59: a turn keeps running after it loses its lock.
- microsoft/duroxide-pg#29 and microsoft/duroxide-pg#44.
- Lenguaje dominante
- Rust
- Estrellas
- 235
- Forks
- 63
- Merge medio
- 2 d 1 h
- PR fusionados (30 d)
- 7
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de microsoft/duroxide
-
enhancement
Dificultad 3/5 Medio día Aptitud para principiantes 70/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 3/5 1-2 días Aptitud para principiantes 74/100
Los mantenedores suelen responder en 1 día
-
One failed session lock renewal loses the session: no retry, no log, no signal to running activitiesAbiertobug
Dificultad 4/5 3-5 días Aptitud para principiantes 30/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 3/5 1-2 días Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 5/5 Más de una semana Aptitud para principiantes 38/100
Los mantenedores suelen responder en 1 día
Todos los issues de microsoft/duroxide
Issues similares
-
Windows docs: pin a tested ConPTY version for Kitty graphics; 1.25.260930003 corrupts large uploadsAbierto
Dificultad 1/5 1-3 horas Aptitud para principiantes 88/100
raphamorim/rio#2021 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
hydro-project/infinity#187 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
near/near-sdk-rs#1676 ·
Los mantenedores suelen responder en 2 días
-
auto:producer auto:security
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
fritzprix/libr-agent#2595 ·
Los mantenedores suelen responder en 1 día
-
area:fs type:fix
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Tripstack-Corp/spyc#1002 ·
Los mantenedores suelen responder en 1 día