You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.