Skip to content

v0.40.0

Choose a tag to compare

@anulum anulum released this 24 Jun 13:00
· 1704 commits to main since this release

Changed

  • Lease expiry no longer scans every claim on each mutation. The state keeps a
    min-heap of leases keyed by expiry, so an expiry pass pops only the leases that
    have actually lapsed instead of walking the whole claim table on every
    heartbeat, claim, update, and release. A renewal's superseded heap entry is
    recognised and skipped by its lease epoch (lazy deletion), and the heap is
    rebuilt when renewal churn grows it past the live-claim count, so its size stays
    bounded. Behaviour is unchanged; only the cost of expiry drops from linear in
    the number of claims to proportional to the number actually expiring.
  • The relay log is now trimmed atomically. The kept tail is written to a
    temporary file and renamed over the log (os.replace, atomic on the same
    filesystem) instead of being rewritten in place, so a crash mid-trim can never
    leave the relay log half-written — a reader always sees either the old log or
    the fully trimmed one.

Added

  • An optional HTTP observability endpoint on the hub. With synapse hub --metrics (or SynapseHub(enable_metrics=True)) the same port also answers
    GET /metrics in the Prometheus text exposition format — connected clients,
    online agents, active claims, resource offers, retained history, blackboard
    tasks, and a monotonic message counter — and GET /health with a small JSON
    liveness document for container probes. Both are served in the hub's event loop
    via the WebSocket server's request hook, so a scrape reads a consistent view of
    the live state with no extra port, thread, or third-party dependency. Off by
    default — a plain hub serves no HTTP.
  • An opt-in retention knob that bounds the durable write log. Resume checkpoints
    and authored findings are committed at full durability and otherwise accumulate
    without bound; compact(store, RetentionPolicy(...), floor_seq=...) (and the
    synapse compact <db> command) keeps the latest N checkpoints per task and
    ages out findings whose validity window closed more than a grace period ago. It
    deletes only events at or below a caller-supplied floor sequence, so a downstream
    ingest cursor at or below the floor never loses an unconsumed event, and a deleted
    sequence is never reused, so a cursor walks the gap. Keeping the latest checkpoint
    per task leaves coordination replay reconstructing each claim exactly as before;
    findings are skipped by replay, so ageing them out never touches coordination
    state. EventStore gains max_seq(), delete(seqs), and vacuum() to support it.

Fixed

  • The idempotency guard now survives a hub restart. The cache that makes a retried
    mutation a no-op — so a reconnecting agent that resends a claim or release it is
    unsure landed replays the original response instead of applying it twice — was
    held only in memory and lost on restart, the one window where a retry is most
    likely. Each remembered key/response is now journalled durably (idempotency
    event, committed at FULL to match the lease mutations it protects) and the
    cache is rebuilt on replay, so the at-most-once guarantee holds across a restart.