Skip to content

feat(sdk/go): add context.Context to Store interface methods#476

Merged
peteski22 merged 8 commits into
mainfrom
feature/add-context-to-store-interface
Jun 25, 2026
Merged

feat(sdk/go): add context.Context to Store interface methods#476
peteski22 merged 8 commits into
mainfrom
feature/add-context-to-store-interface

Conversation

@peteski22

@peteski22 peteski22 commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add context.Context as the first parameter to all Store interface methods
    (Unit, All, Insert, Update, Delete, Query, Stats) so callers can set
    timeouts and cancellation. Close is unchanged — it does no cancellable I/O.
  • Update all three implementations (in-memory, SQLite, PostgreSQL), the
    Client, the conformance suite, and tests.
  • The SQLite store now uses context-aware database/sql methods (QueryContext,
    ExecContext, BeginTx, PrepareContext).
  • Add context.Context to postgres.New constructor, which had the same
    indefinite-blocking problem via context.Background() for pool creation,
    ping, and schema migration.

Fixes #468

Test plan

  • make test-sdk-go — all tests pass
  • make test-cli — all tests pass
  • make lint-sdk-go — 0 issues
  • make lint-cli — 0 issues

Summary by CodeRabbit

  • Bug Fixes
    • Store operations now require and consistently honour context for cancellation and deadlines, including prompt early cancellation.
    • Storage-backed and local persistence paths for confirm/flag/drain/status now use cancellation-aware execution.
    • Store adapters propagate the same context through reads, writes, queries, and statistics for more predictable behaviour.
  • Tests
    • Updated in-memory, SQLite, PostgreSQL, and conformance suites to use the new context-aware operation flow.
  • Documentation
    • Updated PostgreSQL examples and clarified that configured timeouts are an upper bound, with caller deadlines taking precedence.

The Store interface methods accepted no context, forcing the
PostgreSQL adapter to use context.Background() for every pgx
call. A stalled connection could block indefinitely while
holding the store mutex with no way for callers to cancel.

Add context.Context as the first parameter to Unit, All, Insert,
Update, Delete, Query, and Stats. Close is unchanged — it does
no cancellable I/O. All three implementations (memory, SQLite,
PostgreSQL), the Client, the conformance suite, and tests are
updated in lockstep.

The SQLite store now uses context-aware database/sql methods
(QueryContext, ExecContext, BeginTx, PrepareContext).

Fixes #468
postgres.New used context.Background() for pool creation, server
ping, and schema migration — the same indefinite-blocking problem
the Store interface change addressed. Thread caller-provided
context through New, ensureSchema, and stampWriter so callers
can set timeouts on connection setup.
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 27c47e02-249a-4a2a-901b-92916a8e9a4a

📥 Commits

Reviewing files that changed from the base of the PR and between 8a2c03d and b48c13f.

📒 Files selected for processing (2)
  • sdk/go/README.md
  • sdk/go/stores/postgres/README.md

Walkthrough

Go store methods now accept context.Context across the shared interface, client call sites, in-memory adapter, SQLite adapter, and PostgreSQL adapter. The related tests and examples were updated to call the new signatures with context.Background().

Changes

Go store context propagation

Layer / File(s) Summary
Store contract and conformance calls
sdk/go/store.go, sdk/go/storetest/storetest.go, sdk/go/client.go, sdk/go/options.go
Store methods now take context.Context, client calls pass the operation context into local store work, the conformance suite passes context.Background() into each store call, and the timeout documentation reflects caller deadlines.
In-memory store adapter
sdk/go/store_memory.go, sdk/go/store_memory_test.go
The in-memory store methods accept context.Context, check cancellation before locking, and the in-memory tests call the new signatures with context.Background().
SQLite store adapter
sdk/go/store_sqlite.go, sdk/go/store_sqlite_test.go
The SQLite store methods take context.Context and use context-aware database calls, and the SQLite tests pass context.Background() through CRUD, query, stats, and end-to-end cases.
PostgreSQL store adapter
sdk/go/stores/postgres/postgres.go, sdk/go/stores/postgres/postgres_test.go, sdk/go/README.md, sdk/go/stores/postgres/README.md
postgres.New and the exported PostgreSQL store methods accept context.Context, schema setup and writer stamping use the provided context, rollback uses a bounded background timeout, and the tests and README examples cover the new constructor signature and cancellation behaviour.

Possibly related PRs

  • mozilla-ai/cq#409: Updates sdk/go/client.go Status(), which also touches the local stats path that this PR rewires to use ctx.
  • mozilla-ai/cq#422: Introduces the Go Store SPI that this PR changes by adding context.Context to each method.
  • mozilla-ai/cq#462: Adds the PostgreSQL store surface that this PR updates to use contextual database calls.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding context.Context to Store methods across the SDK.
Linked Issues check ✅ Passed The PR satisfies #468 by adding context to Store methods and propagating it through all implementations.
Out of Scope Changes check ✅ Passed No clear out-of-scope code changes are evident; the SQLite, PostgreSQL, client, and test updates all support the context-aware Store refactor.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/add-context-to-store-interface

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Go SDK’s cq.Store SPI to accept context.Context as the first parameter for all cancellable operations, and propagates that change through the SDK client, store implementations, conformance suite, and tests. This addresses the prior risk of indefinite blocking (notably in the PostgreSQL adapter) by allowing callers to enforce timeouts/cancellation.

Changes:

  • Add context.Context as the first argument to all Store interface methods except Close.
  • Update SQLite and PostgreSQL stores to use context-aware DB operations (including database/sql *Context methods and pgx calls).
  • Update the Go SDK client, conformance suite, and store tests to pass contexts through.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
sdk/go/store.go Adds context.Context to all Store methods (except Close) to enable cancellation/deadlines.
sdk/go/client.go Threads caller context through client → store calls for local operations.
sdk/go/store_memory.go Updates in-memory store to satisfy new interface (context ignored).
sdk/go/store_memory_test.go Updates in-memory store tests to pass context.Background().
sdk/go/store_sqlite.go Updates SQLite store methods and helpers to use database/sql context-aware APIs.
sdk/go/store_sqlite_test.go Updates SQLite store tests to pass contexts.
sdk/go/stores/postgres/postgres.go Updates PostgreSQL store API, propagates ctx into pool creation/ping/migrations and all queries.
sdk/go/stores/postgres/postgres_test.go Updates PostgreSQL constructor tests to pass context.
sdk/go/storetest/storetest.go Updates the conformance suite to pass contexts to all store calls.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sdk/go/stores/postgres/postgres.go
Comment thread sdk/go/stores/postgres/postgres.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sdk/go/client.go (1)

185-192: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Apply operationContext in DrainableCount.

Unlike the other client entry points, this method never normalises the caller context before Line 192. That means c.timeout is ignored for Store.All(ctx), and a nil ctx still panics at Line 187. Now that All can perform cancellable backing-store I/O, this path can still block indefinitely.

Suggested fix
 func (c *Client) DrainableCount(ctx context.Context) (int, error) {
-	select {
-	case <-ctx.Done():
-		return 0, ctx.Err()
-	default:
-	}
+	ctx, cancel := c.operationContext(ctx)
+	defer cancel()
+
+	if err := ctx.Err(); err != nil {
+		return 0, err
+	}
 
 	units, err := c.store.All(ctx)
 	if err != nil {
 		return 0, fmt.Errorf("reading local units: %w", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/go/client.go` around lines 185 - 192, The DrainableCount method is using
the caller context directly, so it can ignore c.timeout and still panic on a nil
ctx before calling Store.All. Update Client.DrainableCount to normalize the
input with operationContext, matching the other client entry points, and then
pass that derived context into c.store.All so timeout and cancellation are
consistently applied.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/go/store_memory.go`:
- Line 31: The in-memory store methods on inMemoryStore still ignore ctx, so
cancellation is not honored consistently with the SQLite and PostgreSQL
backends. Update the affected methods, especially All, Query, and Stats, to
perform a pre-flight context check before blocking on s.mu and add loop-level
ctx checks while iterating the store; apply the same pattern to the other
inMemoryStore methods referenced in the diff so Client.Query and DrainableCount
stop behaving differently by backend.

In `@sdk/go/stores/postgres/postgres_test.go`:
- Around line 41-43: Add a regression case in TestNew that calls postgres.New
with an already-cancelled context instead of only context.Background(), so the
test verifies pool creation, ping, and schema setup all respect cancellation.
Use the existing postgres.New test table or add a small separate subtest keyed
off tc.connString, and assert the returned error reflects context cancellation.

---

Outside diff comments:
In `@sdk/go/client.go`:
- Around line 185-192: The DrainableCount method is using the caller context
directly, so it can ignore c.timeout and still panic on a nil ctx before calling
Store.All. Update Client.DrainableCount to normalize the input with
operationContext, matching the other client entry points, and then pass that
derived context into c.store.All so timeout and cancellation are consistently
applied.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a4f8de4b-2b67-494e-a2da-e86073dc27ad

📥 Commits

Reviewing files that changed from the base of the PR and between 633ffb3 and 62c6e0e.

📒 Files selected for processing (9)
  • sdk/go/client.go
  • sdk/go/store.go
  • sdk/go/store_memory.go
  • sdk/go/store_memory_test.go
  • sdk/go/store_sqlite.go
  • sdk/go/store_sqlite_test.go
  • sdk/go/stores/postgres/postgres.go
  • sdk/go/stores/postgres/postgres_test.go
  • sdk/go/storetest/storetest.go

Comment thread sdk/go/store_memory.go Outdated
Comment thread sdk/go/stores/postgres/postgres_test.go
The deferred rollback in Insert and Update used the caller's ctx.
When that ctx is cancelled or times out mid-operation, the rollback
cannot run, and pgx churns the pooled connection instead of
releasing it cleanly.

Extract a rollback helper that discards the transaction with a
short background-derived context, independent of caller
cancellation but still bounded so it cannot block indefinitely.
Guard against future drift back to context.Background() inside New
by asserting that an already-cancelled context aborts connection
setup. Asserts errors.Is(err, context.Canceled) so it holds
regardless of which setup stage observes the cancellation.
The in-memory store discarded ctx, so a cancelled call could still
acquire the mutex and walk the store while the SQLite and Postgres
backends would return early. Add a pre-flight select/default check
to each context-taking method so cancellation behaves consistently
across backends. The store does no blocking I/O, so per-iteration
checks are unnecessary.
operationContext skipped the client timeout entirely when the
caller's context already carried a deadline, making c.timeout a
default-when-unset rather than a ceiling. Always derive from the
caller's context with WithTimeout, which expires at the sooner of
the two — so c.timeout caps every operation without ever extending
a shorter caller deadline.

Also drop the nil-context guard: passing a nil context is a caller
bug and panicking is the idiomatic Go outcome.
Convert the pre-flight cancellation guards across the client entry
points from ctx.Err() to a uniform select/default form, and route
DrainableCount through operationContext like every other entry
point so it honors the client timeout instead of using the raw
caller context. The mid-loop check in Drain stays on ctx.Err()
because a select there would need a labeled break.
@peteski22 peteski22 added sdk sdk-go For issues or PRs related to the Go SDK labels Jun 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sdk/go/client.go (1)

169-177: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use a non-cancellable cleanup context for the post-push delete.

After the remote propose succeeds, Line 176 still uses the caller context for local cleanup. If the deadline fires in that gap, the unit is already persisted remotely but remains in the local store, so the next drain can re-push the same item. The delete needs a short-lived background-derived context so cancellation cannot strand a successfully drained unit locally.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/go/client.go` around lines 169 - 177, The post-push cleanup in the drain
flow still uses the caller’s context for the local delete, which can leave a
successfully proposed unit stranded if the request is canceled before deletion.
Update the cleanup path in c.remote.propose handling within c.store.Delete to
use a short-lived background-derived context for the local delete, so
cancellation or deadline expiry cannot block the cleanup after a successful
remote push.
♻️ Duplicate comments (1)
sdk/go/store_memory.go (1)

31-50: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

The in-memory scans still ignore cancellation after the pre-flight check.

These new select blocks only catch contexts that are already cancelled. Once All, Query, or Stats enter their s.order loops, they never re-check ctx, so a cancelled DrainableCount, Query, or Status call can still walk the whole store while holding s.mu. Add loop-time cancellation checks before cloning/ranking each item so the in-memory backend matches the cancellability promised by the other stores.

Also applies to: 126-166, 170-220

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/go/store_memory.go` around lines 31 - 50, The in-memory store methods
All, Query, and Stats only check ctx before entering their loops, so
cancellation is ignored once iteration starts. Update the implementations in
inMemoryStore to re-check ctx during the s.order traversal, before
cloning/ranking each item and while holding s.mu, and return ctx.Err()
immediately when cancelled. Apply the same pattern across All, Query, and Stats
so DrainableCount, Query, and Status stop promptly instead of scanning the whole
store.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/go/client.go`:
- Around line 511-515: The public client methods are now assuming a non-nil
context, but operationContext still can panic if ctx is nil. Add the nil guard
at the exported method boundary or restore the context.Background() fallback
before calling operationContext, and keep the timeout behavior unchanged for
non-nil callers.

In `@sdk/go/stores/postgres/postgres_test.go`:
- Around line 50-59: The postgres.New examples are stale and still show the old
context-free API. Update the usages in postgres.New-related docs and package
comments to the new postgres.New(ctx, connString) signature, matching the
cancellation-aware form exercised by TestNewRespectsCancelledContext and the New
function in postgres.go. Keep the examples consistent across README.md files and
the postgres package comment so they demonstrate passing a context as the first
argument.

---

Outside diff comments:
In `@sdk/go/client.go`:
- Around line 169-177: The post-push cleanup in the drain flow still uses the
caller’s context for the local delete, which can leave a successfully proposed
unit stranded if the request is canceled before deletion. Update the cleanup
path in c.remote.propose handling within c.store.Delete to use a short-lived
background-derived context for the local delete, so cancellation or deadline
expiry cannot block the cleanup after a successful remote push.

---

Duplicate comments:
In `@sdk/go/store_memory.go`:
- Around line 31-50: The in-memory store methods All, Query, and Stats only
check ctx before entering their loops, so cancellation is ignored once iteration
starts. Update the implementations in inMemoryStore to re-check ctx during the
s.order traversal, before cloning/ranking each item and while holding s.mu, and
return ctx.Err() immediately when cancelled. Apply the same pattern across All,
Query, and Stats so DrainableCount, Query, and Status stop promptly instead of
scanning the whole store.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bfcbe834-1430-45f5-bafe-9cbce56d219b

📥 Commits

Reviewing files that changed from the base of the PR and between 62c6e0e and 8a2c03d.

📒 Files selected for processing (5)
  • sdk/go/client.go
  • sdk/go/options.go
  • sdk/go/store_memory.go
  • sdk/go/stores/postgres/postgres.go
  • sdk/go/stores/postgres/postgres_test.go

Comment thread sdk/go/client.go
Comment thread sdk/go/stores/postgres/postgres_test.go
The README usage snippets still showed the context-free
postgres.New(connString) form. Update both to the new
postgres.New(ctx, connString) signature so the docs match the API.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sdk sdk-go For issues or PRs related to the Go SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add context.Context to Store interface methods

2 participants