From 5109f5fb238dbe6b874a3d071a72cfd82472fab9 Mon Sep 17 00:00:00 2001 From: summer97souls Date: Sun, 21 Jun 2026 01:22:11 +0530 Subject: [PATCH] docs: add CLI section, inspect API, update reconciliation to 0.4.1 API, add usage example --- CHANGELOG.md | 16 ++++++++++++ Docs/PHILOSOPHY.md | 49 +++++++++++++++++++++++++------------ README.md | 24 ++++++++++++++++++ assets/demo.gif | Bin 0 -> 42344 bytes sentinel-py/pyproject.toml | 2 +- 5 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 assets/demo.gif diff --git a/CHANGELOG.md b/CHANGELOG.md index 90e8c3f..9da4b7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ The format loosely follows Keep a Changelog. --- +## 0.4.1 — 2026-06-21 + +### Fixed +- Lease now collapses immediately when `fn()` raises an exception. Previously the lease stayed alive until `hard_ttl_ms` expired, causing callers in that window to see `execution_alive=True` instead of `uncertain=True`. + +### Added +- `sentinel.inspect(key)` — inspect the current state of any lease, returns an `InspectResult` with status, liveness, expiry times, and execution result. +- `sen` CLI tool — `sen inspect ` reads `DATABASE_URL` from environment or `.env` and prints lease state directly to the terminal. +- `sentinel.reconcile` — standalone `Reconcile` class exposed as an attribute on `Sentinel`. Replaces the previous pattern of reconciliation methods on `OnceResult`. + +### Changed +- `reconcile()`, `force_complete()`, and `reset()` no longer require `owner_id` and `fencing_token`. Keys are resolved internally; WHERE clause guards handle safety. +- Reconciliation is no longer exposed on `OnceResult`. Use `sentinel.reconcile` instead. + +--- + ## [0.4.0] - 2026 ### Added diff --git a/Docs/PHILOSOPHY.md b/Docs/PHILOSOPHY.md index 0b36233..69e5d0e 100644 --- a/Docs/PHILOSOPHY.md +++ b/Docs/PHILOSOPHY.md @@ -240,6 +240,29 @@ The `claimed` → `executing` transition is the important one. Before that bound --- +## Inspecting Execution State + +At any point you can inspect the current state of a key directly: + +```python +result = sentinel.inspect("payments:charge:123") + +if result is None: + print("No lease found for this key") +else: + print(result.status) # claimed, executing, completed, reconciling + print(result.lease_alive) # whether the lease is still valid + print(result.lease_expires_at) + print(result.hard_expires_at) + print(result.execution_result) # set once completed +``` + +This is useful for debugging uncertain outcomes, monitoring long-running executions, and building observability on top of Sentinel. + +The `sen` CLI wraps this directly — see the CLI section in the README. + +--- + ## Reconciliation When execution ends up in an uncertain state, Sentinel gives you explicit tools to resolve it rather than forcing a guess. @@ -252,41 +275,37 @@ if result.execution_alive: elif result.uncertain: # Execution truth could not be established. - # Reconciliation tools are exposed on this result. - - result.reconcile(...) # Changes state, required before using force_complete and reset - result.reset(...) # Resets the state, so work can be claimed again for retries - result.force_complete(...) # Marks the work as completed, response object should also be passed + # Use sentinel.reconcile to resolve it explicitly. else: return result.response ``` -Example: -```python -result = sentinel.once(...) +Reconciliation tools are exposed on `sentinel.reconcile`: +```python if result.uncertain: - result.reconcile() + sentinel.reconcile.reconcile(key) # Verify downstream system. payment_exists = check_payment() if payment_exists: - result.force_complete( - response={"ok": True} + sentinel.reconcile.force_complete( + key, + execution_result={"ok": True} ) else: - result.reset() + sentinel.reconcile.reset(key) ``` The typical reconciliation pattern: 1. Detect `result.uncertain` on a result -2. Use `reconcile` to start reconciliation -3. Check your downstream system (did the payment go through?) +2. Call `sentinel.reconcile.reconcile(key)` to enter recovery mode +3. Check your downstream system — did the payment go through? 4. If yes: `force_complete` with the known result -5. If no or unknown: `reset` and let it retry +5. If no or unknown: `reset` and let it be claimed again This is more work than a silent retry. It's also the only approach that doesn't risk charging a customer twice. diff --git a/README.md b/README.md index 3bdf2df..048916d 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Sentinel's primary interface is `once()`, which coordinates execution across com pip install sentinel-coordination ``` +![Sentinel CLI](assets/demo.gif) + Requires Python 3.9+ and a PostgreSQL database. --- @@ -51,6 +53,27 @@ sentinel = Sentinel( --- +## CLI + +Sentinel ships with `sen`, a command-line tool for inspecting lease state directly from your terminal. + +![Sentinel CLI](assets/demo.gif) + +### Inspect a lease + +```bash +sen inspect +``` + +`sen` reads `DATABASE_URL` from your environment or a `.env` file automatically. + +```bash +export DATABASE_URL=postgresql://user:password@localhost/mydb +sen inspect +``` + +--- + ## The Once API `sentinel.once()` is the primary interface. Given a key and a function, it guarantees that function runs **at most once per key** across any number of competing workers and returns the cached result to anyone else who asks. @@ -90,6 +113,7 @@ if result.execution_alive: elif result.uncertain: # Execution truth could not be established. # Use reconciliation tooling if needed. + # Reconciallition tooling documentation is in Docs/philosophy.md else: # If execution_alive and uncertain are both False, diff --git a/assets/demo.gif b/assets/demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..da5dae9dcc93656e36246f7b55bb8dfbe00ad943 GIT binary patch literal 42344 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 z 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 JIr6;_06Y02yypM_ literal 0 HcmV?d00001 diff --git a/sentinel-py/pyproject.toml b/sentinel-py/pyproject.toml index 6cb2db8..132ce70 100644 --- a/sentinel-py/pyproject.toml +++ b/sentinel-py/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "sentinel-coordination" -version = "0.4.0" +version = "0.4.1" description = "PostgreSQL-backed execution coordination primitive for correctness-sensitive distributed work." authors = [ { name = "Sreejay Reddy", email = "reddysreejay@gmail.com" }