Skip to content

Add GetTransaction/CancelTransaction to npackd - #10

Merged
imattau merged 1 commit into
masterfrom
phase2-transactions
Sep 21, 2026
Merged

imattau merged 1 commit into
masterfrom
phase2-transactions

Conversation

@imattau

@imattau imattau commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Summary

  • Install and Update accept "async": true to return {"transaction_id": N} immediately instead of blocking until completion.
  • New GetTransaction { transaction_id } polls a transaction's status: running, succeeded (with result), failed (with error), or cancelled.
  • New CancelTransaction { transaction_id } requests cancellation — cooperative, not forcible. A shared AtomicBool cancellation flag is threaded through InstallRefOptions/ResolverState and checked only at the start of processing each package (before starting the next package in a dependency graph, or the next package in an Update loop) — never mid-download or mid-install of a package already in progress, so a cancelled transaction cannot leave the store half-installed.
  • Synchronous (non-async) Install/Update calls are unaffected — same behavior as before, just now with an unused cancel: None.

Why cooperative cancellation

The previous PR's follow-up notes flagged that raw tokio task abortion is unsafe here: aborting mid-file-write or mid-manifest-write could leave the package store in a half-installed, inconsistent state. This checks a flag only at package boundaries, which is the same "unit of work" granularity the existing dependency-cycle/already-installed checks use.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features (no warnings)
  • cargo test (50 passing), including:
    • install_remote_package_respects_cancellation_before_starting_a_package — a pre-cancelled flag causes an immediate, clean bail before any network/filesystem work
    • transactions_report_running_then_succeeded_and_reject_unknown_ids
    • cancel_transaction_stops_a_cooperative_task
  • Manual smoke test over a real socket:
    • Async Update against an empty store → {"transaction_id":1}GetTransaction reports succeeded with the same array Update would have returned synchronously
    • Async Install of npack's own real release against a real relay, cancelled immediately → GetTransaction reports cancelled before any download started

Not in this PR

Streamed progress events (e.g. per-file download progress) — a client still only sees running until the transaction finishes, not incremental progress. Tracked in the roadmap as remaining Phase 2 work.

🤖 Generated with Claude Code

Install and Update accept "async": true to return {"transaction_id":
N} immediately instead of blocking until completion; GetTransaction
polls a transaction's status (running/succeeded/failed/cancelled).

CancelTransaction is cooperative rather than raw task abortion: a
shared AtomicBool cancellation flag is threaded through
InstallRefOptions/ResolverState and checked only at the start of
processing each package (before starting the next package in a
dependency graph, or the next package in an Update loop) -- never
mid-download or mid-install of a package already in progress, so a
cancelled transaction cannot leave the store half-installed.

Verified end-to-end over a real socket: an async Update against an
empty store completes and reports succeeded via GetTransaction, and
cancelling an in-flight async Install against a real relay before its
resolve step starts reports cancelled.

Streamed progress events (e.g. per-file download progress) remain
future work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@imattau
imattau merged commit 67a29ac into master Sep 21, 2026
3 checks passed
@imattau
imattau deleted the phase2-transactions branch September 21, 2026 01:25
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