with-transaction full-body retry vs with-retry commit-only retry for duplicate writes
0 reputation · 09 Sept 2020, 21:15 UTC
0 reputation · 09 Sept 2020, 21:15 UTC
Goal is to prevent duplicate writes when Racket transactions retry after a conflict while using the documented transaction library.
The library documents with-transaction as automatically retrying the entire body on conflict, which implies re-execution of any code in the body. with-retry is presented as an alternative that retries only the commit phase, reducing re-execution of the body. transaction-commit and transaction-rollback provide explicit control over commit points.
The constraint is non-idempotent side effects that must not repeat across retries. Documentation is unclear on whether writes performed before an explicit transaction-commit are automatically rolled back on retry, and on the exact boundaries of what with-retry re-executes under Racket 8.9+ assumptions.
Is with-retry guaranteed to avoid re-executing body code that performs non-idempotent I/O? Does transaction-commit provide a documented commit guard that isolates writes from retry? What is the documented behavior for side effects performed before an explicit commit when a conflict triggers retry?
With with-retry the body is executed exactly once; on a conflict only the commit phase is retried via transaction-commit. Therefore non‑idempotent I/O placed before the commit point is not re‑executed, assuming the body does not perform side effects after the commit attempt.
With with-transaction the entire body is retried from the start on any conflict, so any I/O inside the body will be repeated.
with-retry splits the transaction into a body phase and a commit phase; retries affect only the commit phase.transaction-commit attempts to commit the current transaction state; it does not act as a guard that rolls back prior writes on retry.transaction-commit are not re‑executed when a conflict triggers a retry under with-retry because the body is not retried.The retry mechanism re‑enters the transaction at the point where the commit phase begins. If the body has already finished, its effects are retained in the transaction log and are not repeated; only the attempt to validate and write the transaction log is repeated.
with-retry block, placing it before a call to transaction-commit.If you have side effects that must occur after the commit attempt (e.g., logging the commit outcome), please confirm whether those effects can be made idempotent or moved before the commit; otherwise the recommendation to use with-retry may need adjustment.
#lang racket
(require racket/transaction)
(with-retry
(begin
(display-to-file "log.txt" "side-effect\n") ; non-idempotent I/O
(transaction-commit))) ; commit attempt
Run the snippet under a controlled conflict and examine log.txt for duplicate lines.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.