Skip to content

v1.57.0

Latest

Choose a tag to compare

@tstirrat15 tstirrat15 released this 20 Oct 19:13
· 1 commit to main since this release

What's Changed

Added

  • Experimental: --experimental-full-relation-cache=enabled turns on the full relation cache. It caches the complete relationship set of a hot object#relation at one revision and serves reads from it, including empty answers, with no datastore query. Off by default. (#3392)
  • Datastore: datastore.SortKeyRevision, an optional extension to datastore.Revision for revision types that are totally ordered. Its AppendSortKey returns an order-preserving, prefix-free byte encoding of the revision, suitable as a key — or as one field of a composite key — in an ordered key/value store; String() offers neither property, being a variable-width decimal. Implemented for the hybrid logical clock, timestamp and transaction ID revision types. Postgres revisions are backed by transaction snapshots and are only partially ordered, so they deliberately do not implement it, and a type assertion is how a consumer discovers that. Supersedes ByteSortable(), which reports the same capability but cannot supply the encoding that satisfies it. (#3319)
  • New spicedb datastore delete-relationships command for bulk-deleting relationships matching a filter, in committed batches. On CockroachDB the deletion advances a primary-key cursor so each batch resumes where the previous one stopped, rather than rescanning the MVCC tombstones left by prior batches — the behavior that degrades a repeated DELETE ... LIMIT n loop to a full scan per batch on a large table. Other engines fall back to a slower non-cursored loop. Every filter flag is required, with <any> as an explicit match-anything token, so a forgotten flag cannot widen a deletion. The underlying capability is exposed on the datastore interface (options.WithCursoredDelete, options.WithDeleteAfter, and DeleteRelationshipsResult.Cursor).
  • The DeleteRelationships API now supports resumable, cursored batch deletion. When optional_limit and optional_allow_partial_deletions are set, the response returns an after_result_cursor; passing it back as optional_cursor on the next call resumes the deletion after the last relationship removed, which on CockroachDB avoids rescanning already-deleted relationships. Datastores that cannot resume a cursored deletion return an error when a cursor is supplied; without a cursor they transparently fall back to the existing non-cursored partial deletion.

Fixed

  • Watch: a relationship filter whose subject filter asks for subjects with no relation (optional_relation with an empty relation) also matched subjects with a relation, such as group:eng#member, so Watch sent updates that the same filter excludes when reading relationships. Watch now applies the same subject relation rules as the datastores. (#3400)
  • Remote dispatch: a hedged Check dispatch that is canceled, or whose deadline passes, before any dispatcher answers now returns the context's error instead of check dispatch has timed out. Clients now receive Canceled or DeadlineExceeded rather than Unknown. (#3398)
  • ReadRelationships/DeleteRelationships: a relationship filter whose resource relation is a permission now returns a clear InvalidArgument error explaining that relationships cannot be filtered on a permission, instead of an opaque "does not have type information" error (ReadRelationships) or silently matching nothing (DeleteRelationships). A subject filter's relation may still legally reference a permission. (#3415)
  • LookupSubjects: avoid quadratic exclusion-list copying when subtracting many concrete subjects from a wildcard.
  • Remote dispatch: canceled LookupResources and LookupSubjects streams now return an error instead of reporting success with incomplete results, preventing partial results from being cached and replayed. (#3380)
  • Remote dispatch: a LookupResources2 request whose cursor is locked to a secondary dispatcher now returns Canceled or DeadlineExceeded when canceled or timed out before the secondary returns any results, instead of an Unknown "no dispatcher returned results" error. (#3397)
  • Remote dispatch: when a secondary dispatcher failed before the primary had started its hedging delay, the primary still waited out the full delay instead of running immediately. It now skips the delay. (#3399)
  • Postgres: DeleteRelationships with a limit no longer takes time proportional to how many relationships share a subject. The rows to soft-delete were selected by their seven key columns and then re-found by the UPDATE, which on a large table resolves through the by-subject index and walks every entry for that subject before filtering; a batch of 1000 could take seconds for a widely-shared subject, or exceed a deadline entirely for a wildcard one. The UPDATE now keys on the physical row address (tableoid, ctid), as the garbage collector already did, so each row is fetched directly. (#3309)
  • MemDB/Datastore: a revision reported with no validity is no longer kept by the optimized revision cache, and we fixed an issue where MemDB's reported validity caused a stale value to be cached. (#3374)
  • MemDB: requests made shortly after startup could fail with object definition not found, or return no results, even though the schema and relationships had already been written. MemDB now advertises its head revision in that case, so committed data is never hidden behind the datastore's own creation. (#3366)
  • MySQL: fixed a crash in the watch API. When reading transaction metadata hit an error part-way through iterating the result rows, that error was dropped and the watch was handed an empty result with no error, which then dereferenced a nil value and took the whole process down with it. The error is now returned to the caller. (#3358)
  • Postgres: fixed connections being handed to queries already broken, which surfaced as timeout: read tcp ...: i/o timeout against a perfectly healthy database, most often under load and shortly after startup. Creating a datastore gave the connection pool the same context it used to bound its own startup checks, and then cancelled it on return - but filling the pool happens on a background goroutine that keeps using that context, so the cancellation landed part-way through opening connections. pgx responds to a cancelled context by setting an immediate deadline on the connection it is working on, and those connections still entered the pool. Pool warm-up now runs on a context of its own, so finishing startup no longer cancels it. The startup checks keep their own 30-second bound. (#3333)
  • Datastore: the wait between transaction retries is now capped at 10 seconds. It previously doubled without limit (25ms, 50ms, 100ms, …), which made --datastore-max-tx-retries an exponential wall-clock budget rather than a count of attempts: at the default of 10 the waits total about 25 seconds, but at 15 they total 14 minutes and at 20 over seven hours. (#3353)
  • Caches: when the amount of available memory could not be determined - for example an AWS ECS task whose memory limit never reaches the cgroup - the fallback used for percent-based budgets was 256KiB rather than the intended 256MiB. A cache configured for 70% of available memory was sized at roughly 183KiB instead of roughly 180MiB. (#3329)
  • Shutdown: on SIGINT or SIGTERM, SpiceDB now reports NOT_SERVING on its gRPC health service and keeps its listeners open for --grpc-shutdown-drain-delay before draining. This gives load balancers and Kubernetes readiness probes time to stop routing to the instance, so new requests do not fail with Unavailable (connection refused) in the window between the signal and the endpoint update. (#3295, #3314)
  • Dispatch: --dispatch-upstream-timeout was ignored; dispatches to other nodes always used a hardcoded 60s timeout. Lowering it now works, so an unresponsive node no longer holds up checks for a full minute. No change on the 60s default. (#3304)

Security

  • Build with Go 1.26.9 and golang.org/x/net v0.60.0, which fix GO-2026-6612, GO-2026-6613 and GO-2026-6617 in the HTTP/2 and net/http code that the gRPC and HTTP servers use. The container images also update grpc_health_probe to v0.4.59, which is built with the same fixes. (#3407)

Docker Images

This release is available at authzed/spicedb:v1.57.0, quay.io/authzed/spicedb:v1.57.0, ghcr.io/authzed/spicedb:v1.57.0