Pixir.SessionLease (pixir v0.1.8)

Copy Markdown View Source

Filesystem-backed writer leases for Pixir Sessions.

Pixir.Session serializes writes inside one BEAM runtime, but a second OS process can still try to resume the same Session and append to the same NDJSON Log. A SessionLease is the cross-process live-capability guard: exactly one writer holder can acquire <workspace>/.pixir/session_leases/<session_id>.json with exclusive create, and Pixir.Log.append/2 refuses competing appends while a lease is present.

The lease is not History and never replaces the Log. It is local runtime evidence used to answer "may this process write now?" Snapshot readers do not need a lease. Stale or ambiguous leases fail closed until an explicit forced-release path records a diagnostic release entry under .pixir/session_leases/releases/.

Summary

Functions

Acquire the writer lease for a Session using atomic exclusive file creation.

Explicitly release a stale or ambiguous writer lease.

Refresh the lease heartbeat for a live Session writer.

Release a writer lease if the current holder still owns it.

Return a parseable Session writer lease status snapshot.

Types

lease()

@type lease() :: map()

Functions

acquire(session_id, opts \\ [])

@spec acquire(
  String.t(),
  keyword()
) :: {:ok, lease()} | {:error, map()}

Acquire the writer lease for a Session using atomic exclusive file creation.

authorize_append(session_id, opts \\ [])

@spec authorize_append(
  String.t(),
  keyword()
) :: :ok | {:error, map()}

Authorize a Log append.

Raw appenders are allowed only when no writer lease exists. Active/stale/ambiguous leases require the matching holder passed as writer_lease: lease.

force_release(session_id, opts \\ [])

@spec force_release(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, map()}

Explicitly release a stale or ambiguous writer lease.

Active leases are refused. The release operation records a durable diagnostic JSON entry before removing the lease file. This is a break-glass path for orphaned writer state, not ordinary startup cleanup.

heartbeat(lease)

@spec heartbeat(lease()) :: {:ok, lease()} | {:error, map()}

Refresh the lease heartbeat for a live Session writer.

release(lease)

@spec release(lease() | nil) :: :ok

Release a writer lease if the current holder still owns it.

status(session_id, opts \\ [])

@spec status(
  String.t(),
  keyword()
) :: {:ok, map()} | {:error, map()}

Return a parseable Session writer lease status snapshot.