From 9fae576babf54bc2c152e7a4b0d2554939987106 Mon Sep 17 00:00:00 2001 From: cjimti Date: Tue, 20 Oct 2026 17:36:26 -0700 Subject: [PATCH] fix: shared advisory-lock session and seven open bugs (#2169) Changes the advisory locks every background loop takes (new internal/advisorylock), /readyz, the database pool floor, the storage forecast, manage_asset update and patch, the call catalog's outcome filter, full-text matching on seven search surfaces (migration 000209), the api/graphql operation ranking, the Google API refusal hint, the api and graphql connection editors, and the deployment guide's image pins; eight tickets: 1. #2169 a replica starved its own pool: each advisory-locked loop held a pooled connection for its whole pass while the pass drew from the same pool. Every try-lock held across work (catalog scan, maps, storage and webhook alerts, retention, capacity, call catalog and audit sweeps, thumbnail sweeps, catalog import, resource reclassification, connlimit slots, the connoauth refresher) now goes on one session per process; a key the process holds is refused, a session whose connection broke is ended, and .semgrep/go-advisory-lock.yml refuses a try-lock taken elsewhere. database.max_open_conns below 4 is refused at startup (dbobs.CheckPoolSize), and /readyz answers 503 database_pool_starved after 30s with no connection handed out. 2. #2203 storage forecast: a store's first day is left out of every fit, the 30-day rate waits for two weeks of history, and a replica that finds a sample within the interval takes none. 3. #2234 manage_asset update and patch grant newly declared references before the new version exists (Declarer.Widen), drop the ones no longer declared once the content is stored, and put them back when the content write fails. 4. #2231 the outcome filter on /api/v1/admin/calls and /api/v1/portal/calls: a count states the outcome as conditions, asks the satisfied rule only of calls an artifact names (citedSet) and reads supersession from one ordered pass over reads; a satisfied page joins the cited set; both run with JIT off. Migration 000208 adds idx_call_records_supersession. On the dev catalog (111,919 records) every outcome answers in 0.32s or less, from 3.6 to 4.7s. 5. #2230 a name is matched by its words: PostgreSQL read "acceptance-1627-1792487495133911000" as "acceptance" and the signed numbers -1627 and -1792487495133911000, so a search by its words never matched. Migration 000209 reads -, _, ., / and : as word breaks beside the text as written in the resource, asset, collection, prompt, knowledge page, script and catalog dataset search functions, the memory index and the folder search. An api or graphql operation not yet embedded is blended at a cosine of zero, as the SQL rankers blend a row the vector arm cannot see. 6. #2224 the deployment guide's compose example pins pgvector/pgvector:pg16, Keycloak 26.7.5 and Trino 453 to digests their registries serve, and make docs-images-check (scripts/docs-image-digests.sh, run in the E2E Nightly) resolves every digest the docs pin. 7. #2237 googlekey.APIHint reads a Google API refusal by its status and details[].reason: SERVICE_DISABLED, ACCESS_TOKEN_SCOPE_INSUFFICIENT, and any other 401 or 403 in Google's shape; no product's message text. 8. #2236 the api and graphql connection editors set oauth_token_lifetime as "Token lifetime" under the OAuth block. Also: certifi 2026.10.19 in docs/requirements.txt (osv); the import ratchet gains the internal/advisorylock edges; the asset references built-in page, docs/server storage, configuration, observability, deployment and api-gateway, docs/memory/overview, docs/portal/admin-connections, CLAUDE.md and llms-full.txt. Closes #2169 Closes #2203 Closes #2234 Closes #2231 Closes #2230 Closes #2224 Closes #2237 Closes #2236 --- .github/workflows/e2e-nightly.yml | 6 + .semgrep/go-advisory-lock.yml | 31 +++ CLAUDE.md | 3 +- Makefile | 6 +- .../admin-admin-connection-oauth-dark.webp | Bin 80700 -> 79382 bytes ...-admin-connection-token-lifetime-dark.webp | Bin 0 -> 76588 bytes .../admin-admin-connection-oauth-light.webp | Bin 83996 -> 82856 bytes ...admin-connection-token-lifetime-light.webp | Bin 0 -> 79858 bytes docs/llms-full.txt | 12 +- docs/memory/overview.md | 2 +- docs/portal/admin-connections.md | 6 + docs/requirements.txt | 6 +- docs/server/api-gateway.md | 5 +- docs/server/configuration.md | 2 +- docs/server/deployment.md | 18 +- docs/server/observability.md | 7 + docs/server/storage.md | 21 +- internal/advisorylock/advisorylock.go | 242 ++++++++++++++++++ .../advisorylock_realdb_integration_test.go | 81 ++++++ internal/advisorylock/advisorylock_test.go | 218 ++++++++++++++++ .../loops_realdb_integration_test.go | 73 ++++++ internal/connlimit/connlimit.go | 54 +--- .../connlimit_realdb_integration_test.go | 8 +- internal/connlimit/shared_test.go | 29 +-- internal/dbobs/dbobs.go | 17 ++ internal/dbobs/dbobs_test.go | 14 + internal/httpserver/health/health.go | 15 +- internal/httpserver/health/pool.go | 83 ++++++ internal/httpserver/health/pool_test.go | 120 +++++++++ internal/httpserver/server.go | 3 + internal/maps/service.go | 23 +- internal/opranking/opranking.go | 12 +- internal/opranking/opranking_test.go | 18 ++ .../outcome_realdb_integration_test.go | 139 ++++++++++ internal/platform/callrecord/postgres.go | 240 +++++++++++++++-- internal/platform/callrecord/postgres_test.go | 101 ++++++++ internal/platform/callrecord/retention.go | 26 +- internal/platform/capacity/capacity.go | 24 +- internal/platform/capacity/capacity_test.go | 2 +- internal/platform/catalogimport/runner.go | 31 +-- internal/platform/catalogscan/loop.go | 33 +-- .../asset-references-and-the-refresh-loop.md | 6 +- internal/platform/levelalert/levelalert.go | 31 +-- .../resourcereclass/resourcereclass.go | 30 +-- internal/platform/retention/retention.go | 28 +- internal/platform/retention/retention_test.go | 8 +- internal/platform/storagecap/forecast.go | 41 ++- internal/platform/storagecap/forecast_test.go | 86 +++++-- internal/platform/storagecap/service.go | 61 ++++- .../service_realdb_integration_test.go | 42 +++ internal/platform/storagecap/service_test.go | 62 ++++- internal/portal/assetrefs/declare.go | 68 +++++ internal/portal/assetrefs/declare_test.go | 61 +++++ internal/thumbdue/thumbdue.go | 36 +-- internal/upstreamauth/googlekey/googlekey.go | 16 +- .../upstreamauth/googlekey/googlekey_test.go | 20 +- pkg/audit/postgres/store.go | 44 +--- pkg/connoauth/locker_test.go | 47 ++++ pkg/connoauth/refresher.go | 39 +-- pkg/database/migrate/migrate_unit_test.go | 2 +- ...8_call_records_supersession_index.down.sql | 1 + ...208_call_records_supersession_index.up.sql | 7 + .../migrations/000209_fts_name_words.down.sql | 82 ++++++ .../migrations/000209_fts_name_words.up.sql | 103 ++++++++ pkg/memory/postgres.go | 5 +- pkg/platform/config.go | 3 +- pkg/platform/config_test.go | 14 + pkg/resource/foldersearch.go | 2 +- .../search_realdb_integration_test.go | 46 ++++ pkg/toolkits/portal/assetrefs.go | 24 ++ pkg/toolkits/portal/assetrefs_test.go | 177 +++++++++++++ pkg/toolkits/portal/patch_handlers.go | 5 + pkg/toolkits/portal/toolkit.go | 5 + scripts/docs-image-digests.sh | 37 +++ test/acceptance/issue_1627_test.go | 8 +- test/acceptance/issue_2169_test.go | 171 +++++++++++++ test/acceptance/issue_2203_test.go | 218 ++++++++++++++++ test/acceptance/issue_2230_test.go | 120 +++++++++ test/acceptance/issue_2231_test.go | 79 ++++++ test/acceptance/issue_2234_test.go | 100 ++++++++ test/acceptance/issue_2236_test.go | 90 +++++++ test/acceptance/issue_2237_test.go | 56 ++++ .../testdata/allowed_internal_imports.txt | 16 +- ui/e2e/interactive/connections-oauth.spec.ts | 5 + ui/e2e/screenshots/route-connections.ts | 19 ++ ui/src/mocks/data/connections.ts | 2 + ui/src/mocks/handlers.ts | 2 + .../connections/ApiGatewayAuthFields.test.tsx | 36 +++ .../connections/ApiGatewayAuthFields.tsx | 44 +++- 89 files changed, 3475 insertions(+), 461 deletions(-) create mode 100644 .semgrep/go-advisory-lock.yml create mode 100644 docs/images/screenshots/dark/admin-admin-connection-token-lifetime-dark.webp create mode 100644 docs/images/screenshots/light/admin-admin-connection-token-lifetime-light.webp create mode 100644 internal/advisorylock/advisorylock.go create mode 100644 internal/advisorylock/advisorylock_realdb_integration_test.go create mode 100644 internal/advisorylock/advisorylock_test.go create mode 100644 internal/advisorylock/loops_realdb_integration_test.go create mode 100644 internal/httpserver/health/pool.go create mode 100644 internal/httpserver/health/pool_test.go create mode 100644 internal/platform/callrecord/outcome_realdb_integration_test.go create mode 100644 pkg/connoauth/locker_test.go create mode 100644 pkg/database/migrate/migrations/000208_call_records_supersession_index.down.sql create mode 100644 pkg/database/migrate/migrations/000208_call_records_supersession_index.up.sql create mode 100644 pkg/database/migrate/migrations/000209_fts_name_words.down.sql create mode 100644 pkg/database/migrate/migrations/000209_fts_name_words.up.sql create mode 100755 scripts/docs-image-digests.sh create mode 100644 test/acceptance/issue_2169_test.go create mode 100644 test/acceptance/issue_2203_test.go create mode 100644 test/acceptance/issue_2230_test.go create mode 100644 test/acceptance/issue_2231_test.go create mode 100644 test/acceptance/issue_2234_test.go create mode 100644 test/acceptance/issue_2236_test.go create mode 100644 test/acceptance/issue_2237_test.go diff --git a/.github/workflows/e2e-nightly.yml b/.github/workflows/e2e-nightly.yml index 5f166de59..9c7912985 100644 --- a/.github/workflows/e2e-nightly.yml +++ b/.github/workflows/e2e-nightly.yml @@ -48,6 +48,12 @@ jobs: go-version: "1.27.2" cache: true + # A digest the docs pin is checked by nothing else, and three that did + # not exist shipped in the deployment guide (#2224). It asks the + # registries, so it runs here rather than in verify. + - name: Resolve the image digests the docs pin + run: make docs-images-check + - name: Start E2E environment run: make e2e-up diff --git a/.semgrep/go-advisory-lock.yml b/.semgrep/go-advisory-lock.yml new file mode 100644 index 000000000..1c50ef04a --- /dev/null +++ b/.semgrep/go-advisory-lock.yml @@ -0,0 +1,31 @@ +rules: + # A try-lock the platform holds across work goes onto the process's one lock + # session, internal/advisorylock (#2169). Each loop used to take its lock on + # a pooled connection of its own and hold it for the whole pass while the + # pass drew its queries from the same pool; with four such loops on a pool of + # five, the passes waited on the pool for their own queries, never released + # their locks, and starved the replica. connoauth's blocking per-call lock is + # the one session lock taken elsewhere, since a lock that waits cannot share + # a session. Test code takes what locks it likes, to stand in for another + # replica. + - id: advisory-try-lock-outside-advisorylock + languages: [go] + severity: ERROR + paths: + include: + - pkg + - internal + - cmd + exclude: + - "*_test.go" + - /internal/advisorylock + - /bench + pattern-regex: pg_try_advisory_lock\( + message: >- + Take a session advisory lock through internal/advisorylock: advisorylock.Try(ctx, db, + advisorylock.ID(key)) and defer the release it returns, and run the locked work on the pool. + A try-lock taken on a connection of its own pins that connection for as long as it is held, + and enough of them starve the pool their holders need to finish (#2169). + metadata: + category: reliability + issue: "#2169" diff --git a/CLAUDE.md b/CLAUDE.md index 52ef13b26..9e303d230 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -203,7 +203,7 @@ mcp-data-platform/ │ ├── connid/ # Connection identity: the instance a connection is stored under, the name a call binds it by, the toolkit serving it, and which half of the config owns it — one Resolver, distinct types │ ├── connview/ # Builds the list_connections view (configured + discovered) │ ├── contenttype/ # Media-type detection and normalization for every content write path -│ ├── database/ # Database utilities (migrate/ = golang-migrate runner + 207 embedded SQL migrations) +│ ├── database/ # Database utilities (migrate/ = golang-migrate runner + 209 embedded SQL migrations) │ ├── embedding/ # Text embedding generation for memory vector search │ ├── indexjobs/ # Postgres-backed, source-kind-agnostic background indexer │ ├── knowledge/ # Unified read path for platform knowledge (federation/ = live toolkit registry adapter) @@ -250,6 +250,7 @@ mcp-data-platform/ │ ├── apigwmetrics/ # The api gateway's outbound HTTP instrumentation as an http.RoundTripper: the connection/status labels, and the persona the call was authorized under, read off the request context the tool call carries (#1615). Holds no gateway types, and was extracted when pkg/toolkits/apigateway reached its package-size budget │ ├── outbound/ # The one transport chain every HTTP client the platform builds is made from (#1895): the User-Agent, a client span named `{kind} {method}` that continues the caller's trace and carries the W3C traceparent to the upstream (off per connection with `trace_propagation: false`), `http_client_requests_total{kind,connection,status_class}` and its histogram, and `egress_blocked_total{reason}` with one WARN when the egress guard under it refuses. `NewClient(Options)` or `Transport(base, opts)`; the recorder is the platform's one Metrics, installed by internal/platform/obs through `SetDefaultMetrics`, and `Metrics()` is how a retry loop counts beside the requests it issues. `.semgrep/go-outbound-client.yml` refuses an `http.Client` built anywhere else │ ├── opsobs/ # The recorder the platform's own operations report through (#1898): installed by internal/platform/obs like outbound's default, read by the authenticator chain (auth_attempts_total), the OIDC JWKS fetch, the HTTP gate's fail-open, browser sign-in and the domain operations (`Start(ctx, Op*)` opens a span under the call and counts domain_operations_total{operation,result}); also the label vocabulary those series use (AuthMethod*, AuthReason*, Denial*, Dependency*, Connection*, Op*, Sink*), kept off pkg/observability's exported surface +│ ├── advisorylock/ # The one session per process every PostgreSQL try-lock held across work is taken on (#2169): the background loops (catalog scan, maps, storage and webhook alerts, retention, capacity, the call catalog and audit sweeps, thumbnail sweeps, catalog import, resource reclassification), connlimit slots and the connoauth refresher. A lock on a pooled connection of its own pinned that connection for the whole pass while the pass drew from the same pool, and four such loops starved a pool of five. `Try(ctx, db, ID(key)|Pair(a,b))` returns a release; a key the process holds is refused, since PostgreSQL would grant it again; the session goes back to the pool with its last lock. `.semgrep/go-advisory-lock.yml` refuses a try-lock taken anywhere else │ ├── bgloop/ # The one way the platform runs work in the background (#1897): `Run` (a timer, a wake channel, a stop channel), `Consume` (a channel of events), `Unit` (one claimed unit of work) and `Listen` (a LISTEN connection's state). Every iteration is counted by result, timed and stamped on success (`background_loop_*{loop}`), gets a span whose context its body logs with, and a skip under another replica's lock is `ErrSkipped`; loop names are constants in names.go. `.semgrep/go-background-loop.yml` refuses a ticker or an infinite loop around a select anywhere else │ ├── objectobs/ # Every object operation on a bucket the platform owns (#1896): `Do` wraps one put/get/get_range/list/delete in a `storage.` client span and one `storage_operations_total{purpose,operation,result,reason}` observation, `Reason` reads a failure into access_denied/bucket_missing/quota_exceeded/not_found/other, and `WithPurpose` lets a caller writing through a shared client (the tile worker, an export, a script's output) report under its own purpose. Called by pkg/portal/s3adapter and the webhook objects; records through outbound.Metrics() │ ├── dbobs/ # The platform's PostgreSQL pool opened through otelsql (#1896): a `postgres.` span per statement inside a traced request (none outside one), `db_client_operation_duration_seconds{operation}` and `db_client_slow_statements_total{operation}`, where the operation is the statement keyword, `vector_search` for a pgvector ranking, or the transaction step. The SQL text is on the span only with `OTEL_TRACES_INCLUDE_DB_STATEMENT=true`; the slow threshold is `MCP_PLATFORM_DB_SLOW_STATEMENT_THRESHOLD` (1s) diff --git a/Makefile b/Makefile index c2535ec61..4886de00d 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ GOVET := $(GO) vet GOFMT := gofmt GOLINT := golangci-lint -.PHONY: all build test lint lint-full fmt clean install help docs-serve docs-build verify verify-release alert-rules-test builtin-pages-check \ +.PHONY: all build test lint lint-full fmt clean install help docs-serve docs-build docs-images-check verify verify-release alert-rules-test builtin-pages-check \ tools-check dead-code mutate patch-coverage patch-coverage-check coverage-summary doc-check acceptance acceptance-release acceptance-check acceptance-release-check release-tag-check schedule-lane schedule-lane-ui realdb-lane state-readers-check e2e-copy-check route-manifest-check posture-check preverify preverify-fast swagger swagger-check verify-checks verify-go verify-static verify-docker verify-ui vet-tags \ semgrep semgrep-diff semgrep-changed codeql sast osv embed-clean migrate-check \ frontend-install frontend-build frontend-build-content-viewer content-viewer-embed \ @@ -546,6 +546,10 @@ patch-coverage-check: @echo "Checking patch coverage..." @PATCH_COVERAGE_THRESHOLD=$(PATCH_COVERAGE_MIN) ./scripts/patch-coverage.sh +## docs-images-check: Resolve every image the docs pin to a digest against its registry (network and Docker; run by the E2E Nightly) +docs-images-check: + @./scripts/docs-image-digests.sh docs + ## doc-check: Fail on orphaned docs, unresolved doc links, or unregistered tool refs; warn on undocumented changes doc-check: @./scripts/doc-check.sh diff --git a/docs/images/screenshots/dark/admin-admin-connection-oauth-dark.webp b/docs/images/screenshots/dark/admin-admin-connection-oauth-dark.webp index c442cd95a8f087b7271340be559ba8cb7ac9e443..fb6b4cc9bb382cc13226a883216aeb58352f9034 100644 GIT binary patch literal 79382 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₇@ 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≻R~Dl81{E)SDZcv7E3{& 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 ib(bmTn8F8O8+beb000000000000000000000000I9)tM+ diff --git a/docs/images/screenshots/dark/admin-admin-connection-token-lifetime-dark.webp b/docs/images/screenshots/dark/admin-admin-connection-token-lifetime-dark.webp new file mode 100644 index 0000000000000000000000000000000000000000..96252c6481b377bfc7479cb05387071f7ccabe11 GIT binary patch literal 76588 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 literal 83996 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 CCYhzK)v2JmR} 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 N00000000000026xh&TWM diff --git a/docs/images/screenshots/light/admin-admin-connection-token-lifetime-light.webp b/docs/images/screenshots/light/admin-admin-connection-token-lifetime-light.webp new file mode 100644 index 0000000000000000000000000000000000000000..ea07f3cccf752c56e1f30a307cb48b6457dc98c6 GIT binary patch literal 79858 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 (VMqL^YW(_7&`b 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, and writes a `platform.startup` span with a child per phase. -`dependency_up{dependency}` (`database`, `semantic`, `query`, `object_storage`, `idp`, `renderer`) is 1 when the dependency answered its last ping; `/readyz` does not read it, so an upstream outage never takes every replica out of a load balancer. The pings re-run at most once per `server.state_probe_interval` (default `1m`), only when scraped, and never hold a scrape. `mcp_platform_connections{kind,state}` counts connections by the state the last call through each one found it in, and sends nothing to find out: `healthy` (the upstream answered), `unreachable` (no answer, or 502/503/504), `auth_failed` (HTTP 401/407 from an API, GraphQL, MCP or Trino upstream; an S3 key or signature refused), `configured` (no call has used it on this replica); read with `max by (kind, state)`. `mcp_platform_personas` counts the registered personas, `search_index_last_indexed_age_seconds{kind}` how long ago each search source last finished indexing. +`dependency_up{dependency}` (`database`, `semantic`, `query`, `object_storage`, `idp`, `renderer`) is 1 when the dependency answered its last ping; `/readyz` does not read it, so an upstream outage never takes every replica out of a load balancer. The replica's own pool is the exception: every connection in use with none handed out within 500ms for 30s answers `/readyz` 503 `database_pool_starved` (#2169). The pings re-run at most once per `server.state_probe_interval` (default `1m`), only when scraped, and never hold a scrape. `mcp_platform_connections{kind,state}` counts connections by the state the last call through each one found it in, and sends nothing to find out: `healthy` (the upstream answered), `unreachable` (no answer, or 502/503/504), `auth_failed` (HTTP 401/407 from an API, GraphQL, MCP or Trino upstream; an S3 key or signature refused), `configured` (no call has used it on this replica); read with `max by (kind, state)`. `mcp_platform_personas` counts the registered personas, `search_index_last_indexed_age_seconds{kind}` how long ago each search source last finished indexing. `domain_operations_total{operation,result}` and `domain_operation_duration_seconds{operation}` count the platform's own operations, each with a span of its name under the calling `tools/call`: `knowledge.apply`, `memory.capture`, `memory.manage`, `search.query`, `search.fetch`, `calls.record`, `calls.reuse`, `calls.promote`, `calls.sweep`, `configstore.read`, `configstore.write`, `resource.upload`, `resource.extract`, `table.register`, `prompt.serve`. `knowledge_changes_total{sink,result}` counts what `apply_knowledge` changed (`catalog`, `knowledge_page`, `agent_instructions`: `applied`/`failed`; `insight`: `created`/`approved`/`rejected`); `search_results_returned_total` sums the hits search returned; archive extraction counts `archive_members_extracted_total`, `archive_extracted_bytes_total` and `archive_refusals_total{reason}`. @@ -2038,7 +2038,7 @@ Lifecycle operations for existing memory records; create new records with `memor Reading memory back moved to the universal `search` tool (see Knowledge Tools): relevance ranking, entity-keyed lookup, and catalog lineage/graph traversal are all served there. The memory toolkit retains `memory_manage` for the write path. -The ranking it uses fuses embedding cosine similarity with a lexical full-text match signal, blended as `0.6 * semantic + 0.4 * lexical`, which improves recall on identifier-heavy content (entity URNs, column names, error codes) over pure vector search. The vector arm uses an `hnsw` ANN index on `memory_records.embedding`; the lexical arm a GIN index on `to_tsvector('english', content)`. When no embedding provider is available it degrades to lexical-only instead of erroring, which also surfaces rows whose embedding is NULL (saved during an outage). +The ranking it uses fuses embedding cosine similarity with a lexical full-text match signal (over `fts_name_words(content)`, which reads `-`, `_`, `.`, `/` and `:` as word breaks beside the text as written, #2230; the names, paths, file names, tags and titles of resources, assets, collections, prompts, knowledge pages, scripts and catalog datasets are read the same way, and a row or API/GraphQL operation not yet embedded is blended at a cosine of zero, so its lexical match outranks every non-match), blended as `0.6 * semantic + 0.4 * lexical`, which improves recall on identifier-heavy content (entity URNs, column names, error codes) over pure vector search. The vector arm uses an `hnsw` ANN index on `memory_records.embedding`; the lexical arm a GIN index on `to_tsvector('english', content)`. When no embedding provider is available it degrades to lexical-only instead of erroring, which also surfaces rows whose embedding is NULL (saved during an outage). Memory registers as a consumer of the shared index-jobs framework (`source_kind = memory`). The synchronous embed-on-write is preserved so a just-saved memory stays immediately recallable; a periodic reconciler backfills embeddings that were missed during an embedder outage (`embedding IS NULL`) or invalidated by a provider model swap (`embedding_model` differs from the current model), and the `memory` kind appears on the admin Indexing dashboard with an indexed/expected coverage ratio. Migration `000054_memory_hybrid_search` adds the `embedding_model` and `embedding_text_hash` breadcrumb columns plus the hnsw and GIN indexes. @@ -2942,7 +2942,7 @@ An external system posts events to `POST /hooks/{source}` (#1870). Each source i # Storage Capacity -Admin > Storage (#2148): every store the platform writes to, used and free, growth, fill date and level. Stores: the database (pg_database_size against `database_limit_bytes`, the operator's, since the platform cannot read the database server's disk), the SeaweedFS cluster (the master's `/dir/status` lists the volume servers, each one's `/status` reports its disks; `seaweedfs.volume_urls` replaces the master's list where it names addresses the platform cannot reach), each bucket (storage_usage summed over purposes, against a budget from the settings, which overrides MCP_PLATFORM_STORAGE_BUDGETS bucket by bucket and also feeds the storage_bucket_budget_bytes gauge), each replica's webhook spool volume (statfs of the spool directory, reported in webhook_spool_state fs_total_bytes/fs_free_bytes). One replica (advisory lock 4713210402) samples every store every 15 minutes (`MCP_PLATFORM_STORAGE_HISTORY_INTERVAL`) into `storage_samples`, kept `history_days` (180). Growth is the least-squares slope over 7 and 30 days in bytes per day, fitted about the means so a store holding one size reads exactly zero; the 7-day rate needs a day of history and the 30-day rate a week (#2201), and each store carries `history_hours`, `rate_7d_min_history_hours` and `rate_30d_min_history_hours` so the page says "Not enough history" with how much there is; the fill date uses the slower growing rate and names it. Settings `GET|PUT /api/v1/admin/settings/storage` (platform_settings section `storage`): database_limit_bytes, budgets, seaweedfs, history_days, used_percent (75/90), days_left (30/7), channels; an absent field keeps its value. Alerts post `storage::used::` and `storage::exhaustion::` and resolve once; a store a pass could not read (the cluster on a failed read, buckets whose capacity it gives, a spool whose replica missed recent reports) keeps its condition. `GET /api/v1/admin/storage` reads everything now (stores, database tables and indexes, buckets by purpose with last listing, reconcile orphaned/dangling, last scan, the SeaweedFS reading or its error, spools); `GET /api/v1/admin/storage/history?store=database|seaweedfs|bucket:|spool:&days=n` reads a store's samples. +Admin > Storage (#2148): every store the platform writes to, used and free, growth, fill date and level. Stores: the database (pg_database_size against `database_limit_bytes`, the operator's, since the platform cannot read the database server's disk), the SeaweedFS cluster (the master's `/dir/status` lists the volume servers, each one's `/status` reports its disks; `seaweedfs.volume_urls` replaces the master's list where it names addresses the platform cannot reach), each bucket (storage_usage summed over purposes, against a budget from the settings, which overrides MCP_PLATFORM_STORAGE_BUDGETS bucket by bucket and also feeds the storage_bucket_budget_bytes gauge), each replica's webhook spool volume (statfs of the spool directory, reported in webhook_spool_state fs_total_bytes/fs_free_bytes). One replica (advisory lock 4713210402) samples every store every 15 minutes (`MCP_PLATFORM_STORAGE_HISTORY_INTERVAL`) into `storage_samples`, kept `history_days` (180); a replica that finds a sample within nine tenths of the interval takes none (#2203). Growth is the least-squares slope over 7 and 30 days in bytes per day, fitted about the means so a store holding one size reads exactly zero; a store's first day (from its first kept sample, when nothing before it was pruned) is left out of every fit as setup, and after it the 7-day rate needs a day of history and the 30-day rate two weeks (#2201, #2203), and each store carries `history_hours`, `rate_7d_min_history_hours` and `rate_30d_min_history_hours` so the page says "Not enough history" with how much there is; the fill date uses the slower growing rate and names it. Settings `GET|PUT /api/v1/admin/settings/storage` (platform_settings section `storage`): database_limit_bytes, budgets, seaweedfs, history_days, used_percent (75/90), days_left (30/7), channels; an absent field keeps its value. Alerts post `storage::used::` and `storage::exhaustion::` and resolve once; a store a pass could not read (the cluster on a failed read, buckets whose capacity it gives, a spool whose replica missed recent reports) keeps its condition. `GET /api/v1/admin/storage` reads everything now (stores, database tables and indexes, buckets by purpose with last listing, reconcile orphaned/dangling, last scan, the SeaweedFS reading or its error, spools); `GET /api/v1/admin/storage/history?store=database|seaweedfs|bucket:|spool:&days=n` reads a store's samples. # Content Types and Viewers @@ -4385,7 +4385,7 @@ No upstream of this class is reachable from the project — every one is custome Signing uses the `jwt_*` keys with two defaults of the grant's own: `jwt_algorithm` defaults to `RS256` (`ES256` alike; `HS256` over `jwt_client_secret` accepted) and `jwt_audience` defaults to `oauth_token_url`. At least one of `jwt_issuer` (usually the application's client id) and `jwt_subject` (the integration user) is required, as under `signed_jwt`; an unset one is omitted from the assertion (#2061). The assertion carries `iss`, `sub`, `aud`, `iat`, `exp` and a random 128-bit hex `jti`, so two replicas exchanging in the same second never present the same assertion to an upstream that refuses replays. -The exchange POSTs `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer` and `assertion=` to `oauth_token_url`. A token from `client_credentials` or `jwt_bearer` whose response states no `expires_in` is reused for `oauth_token_lifetime` (duration string or seconds, default 15m, #1737/#2218); a stated `expires_in` always wins. `oauth_scope_placement` (#2061) says where `oauth_scope` goes: `param` (default) as the `scope` form parameter, `claim` as a `scope` claim in the signed assertion and not on the form (what Google reads), or `both`. `oauth_client_id` and `oauth_client_secret` are optional client authentication placed by `oauth_endpoint_auth_style`; with no secret, a client id goes as a form parameter and no Basic header is sent (an empty Basic credential is one an upstream may refuse). The request uses the same bounded, redirect-refusing, CA-bundle-honoring client as `client_credentials`. The access token is cached by `oauth2.ReuseTokenSource` and a fresh assertion is signed and exchanged as it nears expiry; a response with no `expires_in` is given a 15-minute lifetime (`DefaultUpstreamAccessTokenLifetime`) instead of the unbounded one `golang.org/x/oauth2` would infer, and a `refresh_token` in the response is dropped. `client_credentials` obtains its token under the same rule: both grants wrap their token source in one bounded-expiry stamp inside one `ReuseTokenSource`, so an upstream that omits `expires_in` is re-asked every 15 minutes rather than having its first access token presented for the life of the process (#1737). +The exchange POSTs `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer` and `assertion=` to `oauth_token_url`. A token from `client_credentials` or `jwt_bearer` whose response states no `expires_in` is reused for `oauth_token_lifetime` (duration string or seconds, default 15m, #1737/#2218); a stated `expires_in` always wins. The portal's api and graphql connection editors set it as **Token lifetime** under the OAuth block ("Used when the token endpoint states no expiry"); an empty field stores nothing (#2236). `oauth_scope_placement` (#2061) says where `oauth_scope` goes: `param` (default) as the `scope` form parameter, `claim` as a `scope` claim in the signed assertion and not on the form (what Google reads), or `both`. `oauth_client_id` and `oauth_client_secret` are optional client authentication placed by `oauth_endpoint_auth_style`; with no secret, a client id goes as a form parameter and no Basic header is sent (an empty Basic credential is one an upstream may refuse). The request uses the same bounded, redirect-refusing, CA-bundle-honoring client as `client_credentials`. The access token is cached by `oauth2.ReuseTokenSource` and a fresh assertion is signed and exchanged as it nears expiry; a response with no `expires_in` is given a 15-minute lifetime (`DefaultUpstreamAccessTokenLifetime`) instead of the unbounded one `golang.org/x/oauth2` would infer, and a `refresh_token` in the response is dropped. `client_credentials` obtains its token under the same rule: both grants wrap their token source in one bounded-expiry stamp inside one `ReuseTokenSource`, so an upstream that omits `expires_in` is re-asked every 15 minutes rather than having its first access token presented for the life of the process (#1737). Save-time refusals name the key: no `oauth_token_url`; neither `jwt_issuer` nor `jwt_subject`; an `oauth_scope_placement` other than param, claim or both; key material that does not match `jwt_algorithm` or is not a usable key; `oauth_client_secret` without `oauth_client_id`; an unknown `oauth_endpoint_auth_style`; the `signed_jwt` lifetime and skew rules. `jwt_token_lifetime` is the assertion's lifetime; providers commonly refuse more than a few minutes. An unknown grant is refused as `unknown oauth_grant "..." (want authorization_code, client_credentials or jwt_bearer)`. @@ -4397,7 +4397,7 @@ A Google service account key file is a first-class credential on every HTTP-base `google_service_account_secret` names a stored secret (#2051) holding the file instead, so the private key never enters a tool call or the connection's config. It is read at every token exchange through `secretstore.Store.ConnectionValue`, which requires the connection in the secret's `allow_connections` and refuses a secret with `allow_personas` (the cached token serves every persona on the connection); the kinds bind it per connection with `upstreamauth.BindKeySecrets` (`apigateway.Toolkit.SetSecrets`, `graphql.Toolkit.SetConnectionSecrets`, both attached by `apigwwiring.Secrets`). The token endpoint defaults to `https://oauth2.googleapis.com/token`. Setting both keys is refused. -The connection test (`POST /api/v1/admin/connection-instances/{kind}/{name}/test`) prefixes its detail with `upstreamauth.GrantDetail`: the identity the token was issued for and the scopes the token response reports (or those requested). Google's token refusals carry a hint after the description (`invalid_scope`: check `oauth_scope`; `invalid_grant` signature, not found or disabled: create a new key or check the account; `invalid_grant` short-lived: clock skew), and on an `api` connection a `401`/`403` Google API error body sets the call's `hint` (`SERVICE_DISABLED`: enable the API in the account's project; `PERMISSION_DENIED` or "cannot get profile": grant the account's email inside the product). `steerToExport` now clears only a cut body's hint when api_export is absent, so a decode note or this hint on a whole body survives. The portal editor offers "Google service account" in the auth mode select (`GoogleServiceAccountFields`): Key (Key file upload or Stored secret), Account/Project/Key ID read off the file, Scopes as a list of full URLs, and Delegated user (`jwt_subject`). +The connection test (`POST /api/v1/admin/connection-instances/{kind}/{name}/test`) prefixes its detail with `upstreamauth.GrantDetail`: the identity the token was issued for and the scopes the token response reports (or those requested). Google's token refusals carry a hint after the description (`invalid_scope`: check `oauth_scope`; `invalid_grant` signature, not found or disabled: create a new key or check the account; `invalid_grant` short-lived: clock skew), and on an `api` connection a `401`/`403` Google API error body sets the call's `hint` by its `status` and `details[].reason`, never a product's message text (`SERVICE_DISABLED`: enable the API in the account's project; `ACCESS_TOKEN_SCOPE_INSUFFICIENT`: add the scope to the connection's `oauth_scope`; any other `401` or `403`: grant the account's email inside the product). `steerToExport` now clears only a cut body's hint when api_export is absent, so a decode note or this hint on a whole body survives. The portal editor offers "Google service account" in the auth mode select (`GoogleServiceAccountFields`): Key (Key file upload or Stored secret), Account/Project/Key ID read off the file, Scopes as a list of full URLs, and Delegated user (`jwt_subject`). The admin editor offers the grant on the api and graphql forms (`OAuthFields` `jwtBearer`), rendering the Signed JWT block in its `jwt_bearer` variant. The OAuth status card, with Connect and Refresh now, renders only for the `authorization_code` grant, since the status route answers 409 for every other grant. diff --git a/docs/memory/overview.md b/docs/memory/overview.md index 082b80cc6..edf6de285 100644 --- a/docs/memory/overview.md +++ b/docs/memory/overview.md @@ -103,7 +103,7 @@ Reading memory back is served by the universal `search` tool, which federates me #### Hybrid ranking -The `semantic` strategy fuses two signals per record: the embedding cosine similarity and a lexical full-text match flag, blended as `0.6 * semantic + 0.4 * lexical`. This mirrors the api-gateway ranking precedent and materially improves recall on identifier-heavy content (entity URNs, column names, error codes) where pure vector search underweights an exact token. The vector arm is backed by an `hnsw` ANN index on `memory_records.embedding`; the lexical arm by a GIN index on `to_tsvector('english', content)`. +The `semantic` strategy fuses two signals per record: the embedding cosine similarity and a lexical full-text match flag, blended as `0.6 * semantic + 0.4 * lexical`. This mirrors the api-gateway ranking precedent and materially improves recall on identifier-heavy content (entity URNs, column names, error codes) where pure vector search underweights an exact token. The vector arm is backed by an `hnsw` ANN index on `memory_records.embedding`; the lexical arm by a GIN index on `to_tsvector('english', fts_name_words(content))`. `fts_name_words` adds the text again with `-`, `_`, `.`, `/` and `:` read as spaces, so an identifier such as `orders-2024` matches "orders 2024" as well as itself (#2230). The same reading applies to the names, titles, paths, file names, tags and categories every other surface's full-text search matches: resources, assets and collections, prompts, knowledge pages, managed scripts and catalog datasets. #### Graceful degradation diff --git a/docs/portal/admin-connections.md b/docs/portal/admin-connections.md index 3298182d9..7e7485eed 100644 --- a/docs/portal/admin-connections.md +++ b/docs/portal/admin-connections.md @@ -128,6 +128,10 @@ auth mode reveals it: default) or `params`, which some identity providers require. Shown for the HTTP-based kinds. - **OIDC prompt** (`oauth_prompt`) — `authorization_code` only. +- **Token lifetime** (`oauth_token_lifetime`) — `api` and `graphql`: how long a + token is reused when the token endpoint's response states no `expires_in`, a + duration (`30m`) or seconds. Empty stores nothing, and the default of 15 + minutes applies; a negative value is refused. - **Signed assertion (RFC 7523)** — `jwt_bearer` only: the Signed JWT block below, with the algorithm defaulting to `RS256`, the audience to the token URL, and **Issuer** and **Subject** both required. The issuer is usually the @@ -140,6 +144,8 @@ stored, and the other grants store none. ![OAuth 2.1 credentials](../images/screenshots/light/admin-admin-connection-oauth-light.webp#only-light)![OAuth 2.1 credentials](../images/screenshots/dark/admin-admin-connection-oauth-dark.webp#only-dark) +![Token lifetime](../images/screenshots/light/admin-admin-connection-token-lifetime-light.webp#only-light)![Token lifetime](../images/screenshots/dark/admin-admin-connection-token-lifetime-dark.webp#only-dark) + An `api` connection authored before these keys unified across the kinds may still carry the earlier `oauth2_*` spelling with the grant encoded in the auth mode (`oauth2_authorization_code`). The platform reads both, preferring the diff --git a/docs/requirements.txt b/docs/requirements.txt index 0cf09e6eb..3ec1fbf3e 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -16,9 +16,9 @@ backrefs==7.0 \ --hash=sha256:ca42ce6a49ace3d75684dfa9937f3373902a63284ecb385ce36d15e5dcb41c12 \ --hash=sha256:f2c52955d631b9e1ac4cd56209f0a3a946d592b98e7790e77699339ae01c102a # via mkdocs-material -certifi==2026.6.17 \ - --hash=sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432 \ - --hash=sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db +certifi==2026.10.19 \ + --hash=sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae \ + --hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b # via requests charset-normalizer==3.4.9 \ --hash=sha256:0327fcd59a935777d83410750c50600ee9571af2846f71ce40f25b13da1ef380 \ diff --git a/docs/server/api-gateway.md b/docs/server/api-gateway.md index 6fe85a1db..197f3ca9b 100644 --- a/docs/server/api-gateway.md +++ b/docs/server/api-gateway.md @@ -620,9 +620,10 @@ The save is refused, naming the field and never a value, when the file is not JS | Token `400 invalid_grant` "Invalid JWT Signature" or "account not found" | The key was deleted or disabled, or the account was removed | create a new key, or check the account still exists | | Token `400 invalid_grant` "Token must be a short-lived token" | Clock skew | check the host clock and `jwt_issued_at_skew` | | API `403` with reason `SERVICE_DISABLED` | The API is not enabled in the account's Cloud project | enable it there | -| API `403 PERMISSION_DENIED`, or `401` "cannot get profile" | The token is valid but the account has no access in the product | grant the account's email access inside the product | +| API `403` with reason `ACCESS_TOKEN_SCOPE_INSUFFICIENT` | The token does not carry the scope this API needs | add the scope to the connection's `oauth_scope` | +| Any other API `401` or `403` in Google's error shape (`PERMISSION_DENIED`, `UNAUTHENTICATED`, ...) | The token is valid but the account has no access in the product | grant the account's email access inside the product | -A token refusal raises the connection's alert like any `jwt_bearer` refusal. The two API refusals arrive on a data call rather than at the token endpoint, so they are the call's `hint` on an `api` connection, not an authentication failure. +A token refusal raises the connection's alert like any `jwt_bearer` refusal. The API refusals arrive on a data call rather than at the token endpoint, so they are the call's `hint` on an `api` connection, not an authentication failure. Pick `signed_jwt` when the upstream validates the client-minted JWT itself, and `jwt_bearer` when it exchanges the JWT for a token of its own; [Signed JWT upstreams](signed-jwt-auth.md#signed_jwt-or-the-jwt_bearer-grant) compares the two. diff --git a/docs/server/configuration.md b/docs/server/configuration.md index 3f46c9b14..f1d90385f 100644 --- a/docs/server/configuration.md +++ b/docs/server/configuration.md @@ -430,7 +430,7 @@ database: | Field | Type | Default | Description | |-------|------|---------|-------------| | `dsn` | string | - | PostgreSQL connection string | -| `max_open_conns` | int | `25` | Maximum open database connections | +| `max_open_conns` | int | `25` | Maximum open database connections. At least `4`: one for the session every background lock shares, one for a locked pass, and two for requests; a smaller value is refused at startup | !!! note "What the database unlocks" Setting `dsn` enables audit logging, knowledge capture, session externalization, and OAuth persistence. Without it, these features degrade to in-memory or noop implementations. diff --git a/docs/server/deployment.md b/docs/server/deployment.md index 63b148cf9..c8eddaabb 100644 --- a/docs/server/deployment.md +++ b/docs/server/deployment.md @@ -34,9 +34,10 @@ Create a `docker-compose.yml`: ```yaml services: - # PostgreSQL for metadata storage + # PostgreSQL for metadata storage, with pgvector (the platform's migrations + # create the vector extension) postgres: - image: postgres:16-alpine@sha256:acf5271bce6b4b62e352341e3b175c2b1e9e0b6f6e3f2e7e3b7f8c9d0e1f2a3b + image: pgvector/pgvector:pg16@sha256:7b822b0aac60967beb1ea5e576b8602c94c300a157d187f385ae3e0da199b90a environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} @@ -52,15 +53,15 @@ services: # Keycloak for authentication keycloak: - image: quay.io/keycloak/keycloak:24.0@sha256:b3c4a5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4 + image: quay.io/keycloak/keycloak:26.7.5@sha256:37dbaf6f0722c9ec246335f36e1ef8b2e6cb960f7c27e0d8c615121a3d475a85 command: start-dev --import-realm environment: KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak KC_DB_USERNAME: postgres KC_DB_PASSWORD: ${POSTGRES_PASSWORD:-postgres} - KEYCLOAK_ADMIN: admin - KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin} + KC_BOOTSTRAP_ADMIN_USERNAME: admin + KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin} volumes: - ./keycloak-realm.json:/opt/keycloak/data/import/realm.json ports: @@ -71,7 +72,7 @@ services: # Trino for SQL queries trino: - image: trinodb/trino:440@sha256:d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5 + image: trinodb/trino:453@sha256:86f7a156aeeca1dda3a1ba1e97474913d10c75f8fb7cda0da1d29a52b5731e0c ports: - "8081:8080" volumes: @@ -519,7 +520,10 @@ spec: ``` `/readyz` reports `draining` (503) as soon as SIGTERM arrives, so the load -balancer stops routing to a terminating pod before the drain begins; +balancer stops routing to a terminating pod before the drain begins, and +`database_pool_starved` (503) when the replica's database pool has handed out +no connection for 30 seconds +([Observability](observability.md#authentication-configuration-and-platform-state)); `/healthz` stays 200 for as long as the process is alive. Size the probe and resource figures from the [Tuning and Scaling guide](../reference/tuning-and-scaling.md), which covers diff --git a/docs/server/observability.md b/docs/server/observability.md index 8b5143917..3ac61a317 100644 --- a/docs/server/observability.md +++ b/docs/server/observability.md @@ -700,6 +700,13 @@ would take every replica out of the load balancer at once during an upstream outage, including the routes that do not need that upstream. Alert on `dependency_up == 0` instead. +The one exception is the replica's own database pool. When every connection +of it has been in use, with none handed out within half a second of being +asked, for 30 seconds, `/readyz` answers 503 `database_pool_starved` and logs +the `database pool starved` WARN: the replica cannot serve anything that reads +the database, and another replica may. A database that is down is not this: +its pool opens no connections, and the replica stays ready (#2169). + **Connections and personas.** `mcp_platform_connections{kind, state}` counts the connections of every kind that lists them by the state the last call through each one found it in. Nothing is sent to an upstream to find diff --git a/docs/server/storage.md b/docs/server/storage.md index 52a0b9959..e0fd77538 100644 --- a/docs/server/storage.md +++ b/docs/server/storage.md @@ -19,16 +19,19 @@ A store with no capacity is listed with its usage and growth and no fill date; i ## Growth and when a store fills -One replica at a time samples every store every 15 minutes +One replica samples every store every 15 minutes (`MCP_PLATFORM_STORAGE_HISTORY_INTERVAL` overrides it) and keeps each sample -for the settings' **History days** (default 180). Growth is the least-squares -slope of the samples over the last 7 and the last 30 days, in bytes per day. -The 7-day rate waits for a day of history and the 30-day rate for a week: a -new install's first hours are setup (migrations, the built-in knowledge pages -and their embeddings, the first catalog scan), not growth, and a 30-day rate -over the same few hours as the 7-day one would only repeat it. Until then the -page says **Not enough history** with how much there is and how much the rate -needs. A store holding one size grows at exactly zero. The fill date uses the +for the settings' **History days** (default 180). Every replica runs the loop, +and one that finds a sample taken within the interval takes none of its own, +so each tick has one sample. Growth is the least-squares slope of the samples +over the last 7 and the last 30 days, in bytes per day. A store's first day is +left out of every fit: a new install's first hours are setup (migrations, the +built-in knowledge pages and their embeddings, seeding, the first catalog +scan), not growth. After it, the 7-day rate waits for a day of history and the +30-day rate for two weeks, so the 30-day rate is read from at least twice the +history the 7-day one is and never repeats it. Until then the page says **Not +enough history** with how much there is and how much the rate needs, the first +day included. A store holding one size grows at exactly zero. The fill date uses the slower of the two that are growing, so a burst does not bring the date in, and the page says which it used. A store that is not growing has no fill date. diff --git a/internal/advisorylock/advisorylock.go b/internal/advisorylock/advisorylock.go new file mode 100644 index 000000000..fb281e520 --- /dev/null +++ b/internal/advisorylock/advisorylock.go @@ -0,0 +1,242 @@ +// Package advisorylock holds the platform's PostgreSQL session advisory locks +// on one database session per process (#2169). +// +// An advisory lock belongs to the session that took it, so a lock held for a +// background pass used to pin a pooled connection of its own for the whole +// pass, while the pass drew its queries from the same pool. Each locked loop +// added one more pinned connection. With four loops locked on a pool of five, +// the passes waited on the pool for their own queries, never finished, never +// released their locks, and starved every request on the replica. +// +// PostgreSQL lets one session hold any number of advisory locks, so every +// try-lock the process takes goes onto one Session: however many loops hold +// a lock, together they pin one connection, and the session goes back to the +// pool when the last lock is released. The pass itself runs on the pool, never +// on the lock's session. +// +// A session lock is reentrant in PostgreSQL: the session holding a key is +// granted it again. A Session therefore refuses a key the process already +// holds, so two goroutines of one process exclude each other as two replicas +// do. +package advisorylock + +import ( + "context" + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "log/slog" + "sync" + "time" + + "github.com/txn2/mcp-data-platform/internal/logsan" +) + +// statementTimeout bounds one lock or unlock statement. It runs on a context +// detached from the caller's, since a statement canceled mid-flight can end +// the session and with it every lock the process holds. +const statementTimeout = 5 * time.Second + +// Key is one advisory lock: a single bigint, or the two-integer form, which +// PostgreSQL keeps in a key space of its own. +type Key struct { + id int64 + space int32 + n int32 + pair bool +} + +// ID is the lock keyed by one bigint. +func ID(id int64) Key { return Key{id: id} } + +// Pair is the lock keyed by two integers. +func Pair(space, n int32) Key { return Key{space: space, n: n, pair: true} } + +// statement is the query taking (or, with unlock, releasing) k. +func (k Key) statement(unlock bool) (query string, args []any) { + fn := "pg_try_advisory_lock" + if unlock { + fn = "pg_advisory_unlock" + } + if k.pair { + return "SELECT " + fn + "($1, $2)", []any{k.space, k.n} + } + return "SELECT " + fn + "($1)", []any{k.id} +} + +// Session is the one database session a process takes its advisory locks on. +// It is safe for concurrent use. +type Session struct { + db *sql.DB + + mu sync.Mutex + // conn is the session, nil while no lock is held. + conn *sql.Conn + // gen counts the sessions opened; a release from an earlier one is a lock + // that ended with its session. + gen uint64 + held map[Key]struct{} +} + +// New builds a Session over db. Production code uses For, which keeps one +// per database handle; New is for a test that stands two replicas on one. +func New(db *sql.DB) *Session { + return &Session{db: db, held: map[Key]struct{}{}} +} + +//nolint:gochecknoglobals // one lock session per database handle in the process, which is the point +var sessions sync.Map + +// For is the process's lock session over db. +func For(db *sql.DB) *Session { + if s, ok := sessions.Load(db); ok { + return s.(*Session) //nolint:forcetypeassert,errcheck // only *Session is stored + } + s, _ := sessions.LoadOrStore(db, New(db)) + return s.(*Session) //nolint:forcetypeassert,errcheck // only *Session is stored +} + +// Try takes key on db's lock session; see Session.Try. +func Try(ctx context.Context, db *sql.DB, key Key) (release func(), ok bool, err error) { + return For(db).Try(ctx, key) +} + +// Try takes key without waiting. ok is false when another session holds it +// or this process already does. release gives it back and is safe to call +// more than once; it does nothing when the session ended in the meantime, +// since that released the lock. +func (s *Session) Try(ctx context.Context, key Key) (release func(), ok bool, err error) { + if err := ctx.Err(); err != nil { + return nil, false, err //nolint:wrapcheck // the caller's own context + } + s.mu.Lock() + defer s.mu.Unlock() + if err := s.open(ctx); err != nil { + return nil, false, err + } + if _, mine := s.held[key]; mine { + s.closeIfIdle() + return nil, false, nil + } + got, err := s.take(ctx, key) + if err != nil { + // A statement that failed took nothing. A session whose connection + // broke has lost every lock on it, and is ended so the next take + // opens another rather than failing on it until its holders finish. + if errors.Is(err, driver.ErrBadConn) || errors.Is(err, sql.ErrConnDone) { + s.lose(ctx, "the lock session's connection broke") + } + s.closeIfIdle() + return nil, false, fmt.Errorf("taking the advisory lock: %w", err) + } + if !got { + s.closeIfIdle() + return nil, false, nil + } + s.held[key] = struct{}{} + gen := s.gen + var once sync.Once + return func() { once.Do(func() { s.release(ctx, key, gen) }) }, true, nil +} + +// Held reports whether any session, this process's included, holds key. +func (s *Session) Held(ctx context.Context, key Key) (bool, error) { + s.mu.Lock() + _, mine := s.held[key] + s.mu.Unlock() + if mine { + return true, nil + } + release, ok, err := s.Try(ctx, key) + if err != nil || !ok { + return err == nil, err + } + release() + return false, nil +} + +// open takes the session from the pool when none is open. It is called with +// mu held and gives mu up while it waits on the pool, so a release is never +// held behind a wait for a connection. +func (s *Session) open(ctx context.Context) error { + if s.conn != nil { + return nil + } + s.mu.Unlock() + conn, err := s.db.Conn(ctx) + s.mu.Lock() + if err != nil { + return fmt.Errorf("acquiring the lock session: %w", err) + } + if s.conn != nil { + _ = conn.Close() + return nil + } + s.conn = conn + s.gen++ + return nil +} + +// take runs key's try-lock statement on the session. +func (s *Session) take(ctx context.Context, key Key) (bool, error) { + stmtCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), statementTimeout) + defer cancel() + q, args := key.statement(false) + var got bool + err := s.conn.QueryRowContext(stmtCtx, q, args...).Scan(&got) + return got, err //nolint:wrapcheck // the caller names the statement +} + +// unlock runs key's unlock statement on the session. +func (s *Session) unlock(ctx context.Context, key Key) error { + stmtCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), statementTimeout) + defer cancel() + q, args := key.statement(true) + _, err := s.conn.ExecContext(stmtCtx, q, args...) + return err //nolint:wrapcheck // the caller names the statement +} + +// release gives key back, unless the session it was taken on has ended. +func (s *Session) release(ctx context.Context, key Key, gen uint64) { + s.mu.Lock() + defer s.mu.Unlock() + if gen != s.gen || s.conn == nil { + return + } + if _, mine := s.held[key]; !mine { + return + } + delete(s.held, key) + if err := s.unlock(ctx, key); err != nil { + // The session may still hold the lock; ending it is what releases it. + slog.WarnContext(ctx, "advisory unlock failed; ending the lock session", + "error", logsan.SanitizeForLog(err.Error())) + s.lose(ctx, "an unlock failed") + return + } + s.closeIfIdle() +} + +// closeIfIdle returns the session to the pool when it holds no lock. +func (s *Session) closeIfIdle() { + if len(s.held) == 0 && s.conn != nil { + _ = s.conn.Close() + s.conn = nil + } +} + +// lose ends the session, which releases every lock on it, and drops it from +// the pool. A lock held when it ends is reported, since its holder still +// runs. +func (s *Session) lose(ctx context.Context, why string) { + if n := len(s.held); n > 0 { + slog.WarnContext(ctx, "advisory lock session ended with locks held", "reason", why, "locks", n) + } + if s.conn != nil { + _ = s.conn.Raw(func(any) error { return driver.ErrBadConn }) + _ = s.conn.Close() + s.conn = nil + } + s.held = map[Key]struct{}{} +} diff --git a/internal/advisorylock/advisorylock_realdb_integration_test.go b/internal/advisorylock/advisorylock_realdb_integration_test.go new file mode 100644 index 000000000..517844b33 --- /dev/null +++ b/internal/advisorylock/advisorylock_realdb_integration_test.go @@ -0,0 +1,81 @@ +//go:build integration + +package advisorylock + +import ( + "context" + "database/sql" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/txn2/mcp-data-platform/internal/testdb" +) + +// The production keys of the loops that held a lock at once on the replica +// #2169 reported, and the others that take one, more locks than the pool has +// connections. +var loopKeys = []int64{ + 4713210201, // catalog scan + 4713210301, // maps + 4713210402, // storage capacity alerts + 4713210403, // webhook receiver alerts + 4713210401, // capacity listing + 4713210001, // call catalog sweep +} + +// TestRealDB_LockedPassesFinishOnASmallPool is #2169: a pool of five, six +// passes each holding its lock while it runs its statements, and a request on +// the side. With a session per lock, five locks held every connection, the +// sixth waited for one, and no pass could run a statement; on the shared +// session every pass finishes and the request is served while they run. +func TestRealDB_LockedPassesFinishOnASmallPool(t *testing.T) { + db := testdb.New(t) + db.SetMaxOpenConns(5) + s := New(db) + baseline := db.Stats().InUse // what the harness itself holds + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + var ( + holding sync.WaitGroup + done sync.WaitGroup + ) + allHeld := make(chan struct{}) + holding.Add(len(loopKeys)) + for _, key := range loopKeys { + done.Go(func() { + release, ok, err := s.Try(ctx, ID(key)) + holding.Done() + if !assert.NoError(t, err) || !assert.True(t, ok, "key %d", key) { + return + } + defer release() + <-allHeld + assert.NoError(t, pass(ctx, db), "key %d", key) + }) + } + holding.Wait() + assert.Equal(t, 1, db.Stats().InUse-baseline, "six locks held on one connection") + close(allHeld) + + var answer int + require.NoError(t, db.QueryRowContext(ctx, "SELECT 1").Scan(&answer), "a request while every pass runs") + done.Wait() + require.NoError(t, ctx.Err(), "the passes finished") + assert.Equal(t, 0, db.Stats().InUse-baseline, "the session went back to the pool with the last lock") +} + +// pass runs a few statements one after another, each on a connection from +// the pool. +func pass(ctx context.Context, db *sql.DB) error { + for range 3 { + if _, err := db.ExecContext(ctx, "SELECT pg_sleep(0.05)"); err != nil { + return err + } + } + return nil +} diff --git a/internal/advisorylock/advisorylock_test.go b/internal/advisorylock/advisorylock_test.go new file mode 100644 index 000000000..dc5dc181d --- /dev/null +++ b/internal/advisorylock/advisorylock_test.go @@ -0,0 +1,218 @@ +package advisorylock + +import ( + "context" + "database/sql/driver" + "errors" + "regexp" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + lockQ = regexp.QuoteMeta("SELECT pg_try_advisory_lock($1)") + unlockQ = regexp.QuoteMeta("SELECT pg_advisory_unlock($1)") + pairLockQ = regexp.QuoteMeta("SELECT pg_try_advisory_lock($1, $2)") + pairFreeQ = regexp.QuoteMeta("SELECT pg_advisory_unlock($1, $2)") + errDown = errors.New("down") +) + +func newMock(t *testing.T) (*Session, sqlmock.Sqlmock) { + t.Helper() + db, mock, err := sqlmock.New() + require.NoError(t, err) + t.Cleanup(func() { _ = db.Close() }) + return New(db), mock +} + +func granted(got bool) *sqlmock.Rows { return sqlmock.NewRows([]string{"l"}).AddRow(got) } + +// Two locks share the session, which goes back to the pool when the last is +// released, and a release is safe to call twice. +func TestTry_TakesAndReleases(t *testing.T) { + s, mock := newMock(t) + ctx := context.Background() + mock.ExpectQuery(lockQ).WithArgs(int64(1)).WillReturnRows(granted(true)) + mock.ExpectQuery(lockQ).WithArgs(int64(2)).WillReturnRows(granted(true)) + mock.ExpectExec(unlockQ).WithArgs(int64(1)).WillReturnResult(sqlmock.NewResult(0, 0)) + mock.ExpectExec(unlockQ).WithArgs(int64(2)).WillReturnResult(sqlmock.NewResult(0, 0)) + + first, ok, err := s.Try(ctx, ID(1)) + require.NoError(t, err) + require.True(t, ok) + second, ok, err := s.Try(ctx, ID(2)) + require.NoError(t, err) + require.True(t, ok) + assert.Equal(t, 1, s.db.Stats().InUse, "two locks hold one connection") + + first() + first() + assert.Equal(t, 1, s.db.Stats().InUse, "a lock still held keeps the session") + second() + assert.Equal(t, 0, s.db.Stats().InUse, "the session goes back to the pool with its last lock") + require.NoError(t, mock.ExpectationsWereMet()) +} + +// A key this process holds is refused without asking the database, since +// PostgreSQL would grant the holding session the key again. +func TestTry_RefusesAKeyThisProcessHolds(t *testing.T) { + s, mock := newMock(t) + ctx := context.Background() + mock.ExpectQuery(lockQ).WithArgs(int64(7)).WillReturnRows(granted(true)) + release, ok, err := s.Try(ctx, ID(7)) + require.NoError(t, err) + require.True(t, ok) + + _, ok, err = s.Try(ctx, ID(7)) + require.NoError(t, err) + assert.False(t, ok, "a second holder in one process") + + mock.ExpectExec(unlockQ).WithArgs(int64(7)).WillReturnResult(sqlmock.NewResult(0, 0)) + release() + require.NoError(t, mock.ExpectationsWereMet()) +} + +// A key another session holds is refused, and the session is not kept for it. +func TestTry_AnotherSessionHoldsIt(t *testing.T) { + s, mock := newMock(t) + mock.ExpectQuery(lockQ).WillReturnRows(granted(false)) + _, ok, err := s.Try(context.Background(), ID(3)) + require.NoError(t, err) + assert.False(t, ok) + assert.Equal(t, 0, s.db.Stats().InUse) + require.NoError(t, mock.ExpectationsWereMet()) +} + +// The two-integer form takes and releases its own statements. +func TestTry_PairKey(t *testing.T) { + s, mock := newMock(t) + mock.ExpectQuery(pairLockQ).WithArgs(int32(9), int32(2)).WillReturnRows(granted(true)) + mock.ExpectExec(pairFreeQ).WithArgs(int32(9), int32(2)).WillReturnResult(sqlmock.NewResult(0, 0)) + release, ok, err := s.Try(context.Background(), Pair(9, 2)) + require.NoError(t, err) + require.True(t, ok) + release() + require.NoError(t, mock.ExpectationsWereMet()) +} + +// A failed take is an error and holds nothing; a done context asks nothing; +// a pool that cannot open a session says so. +func TestTry_Failures(t *testing.T) { + s, mock := newMock(t) + mock.ExpectQuery(lockQ).WillReturnError(errDown) + _, ok, err := s.Try(context.Background(), ID(1)) + require.ErrorIs(t, err, errDown) + assert.False(t, ok) + assert.Equal(t, 0, s.db.Stats().InUse) + + done, cancel := context.WithCancel(context.Background()) + cancel() + _, _, err = s.Try(done, ID(1)) + require.ErrorIs(t, err, context.Canceled) + require.NoError(t, mock.ExpectationsWereMet()) + + _ = s.db.Close() + _, _, err = s.Try(context.Background(), ID(1)) + require.ErrorContains(t, err, "acquiring the lock session") +} + +// An unlock that fails ends the session, since a session that may still hold +// the lock must not go back to the pool; a lock that ended with it releases +// as a no-op, and the next take opens a new session. +func TestRelease_AFailedUnlockEndsTheSession(t *testing.T) { + s, mock := newMock(t) + ctx := context.Background() + mock.ExpectQuery(lockQ).WithArgs(int64(1)).WillReturnRows(granted(true)) + mock.ExpectQuery(lockQ).WithArgs(int64(2)).WillReturnRows(granted(true)) + mock.ExpectExec(unlockQ).WithArgs(int64(1)).WillReturnError(errDown) + + first, _, err := s.Try(ctx, ID(1)) + require.NoError(t, err) + second, _, err := s.Try(ctx, ID(2)) + require.NoError(t, err) + gen := s.gen + first() + assert.Nil(t, s.conn, "the session ended") + assert.Empty(t, s.held, "every lock on it ended with it") + second() // no statement: its lock ended with the session + require.NoError(t, mock.ExpectationsWereMet()) + assert.Equal(t, gen, s.gen, "nothing reopened the session") +} + +// Held answers from the process for a key it holds, and otherwise asks the +// database by taking the key and giving it straight back. +func TestHeld(t *testing.T) { + s, mock := newMock(t) + ctx := context.Background() + + mock.ExpectQuery(lockQ).WithArgs(int64(5)).WillReturnRows(granted(true)) + mock.ExpectExec(unlockQ).WithArgs(int64(5)).WillReturnResult(sqlmock.NewResult(0, 0)) + held, err := s.Held(ctx, ID(5)) + require.NoError(t, err) + assert.False(t, held, "free") + + mock.ExpectQuery(lockQ).WithArgs(int64(5)).WillReturnRows(granted(false)) + held, err = s.Held(ctx, ID(5)) + require.NoError(t, err) + assert.True(t, held, "another replica holds it") + + mock.ExpectQuery(lockQ).WithArgs(int64(5)).WillReturnRows(granted(true)) + release, _, err := s.Try(ctx, ID(5)) + require.NoError(t, err) + held, err = s.Held(ctx, ID(5)) + require.NoError(t, err) + assert.True(t, held, "this process holds it") + + mock.ExpectExec(unlockQ).WithArgs(int64(5)).WillReturnResult(sqlmock.NewResult(0, 0)) + release() + + mock.ExpectQuery(lockQ).WillReturnError(errDown) + _, err = s.Held(ctx, ID(5)) + require.ErrorIs(t, err, errDown) + require.NoError(t, mock.ExpectationsWereMet()) +} + +// For keeps one session per database handle, and Try takes on it. +func TestFor_OneSessionPerHandle(t *testing.T) { + db, mock, err := sqlmock.New() + require.NoError(t, err) + t.Cleanup(func() { _ = db.Close() }) + other, _, err := sqlmock.New() + require.NoError(t, err) + t.Cleanup(func() { _ = other.Close() }) + + assert.Same(t, For(db), For(db)) + assert.NotSame(t, For(db), For(other)) + + mock.ExpectQuery(lockQ).WithArgs(int64(4)).WillReturnRows(granted(true)) + mock.ExpectExec(unlockQ).WithArgs(int64(4)).WillReturnResult(sqlmock.NewResult(0, 0)) + release, ok, err := Try(context.Background(), db, ID(4)) + require.NoError(t, err) + require.True(t, ok) + _, ok, err = For(db).Try(context.Background(), ID(4)) + require.NoError(t, err) + assert.False(t, ok, "Try and For share the session") + release() + require.NoError(t, mock.ExpectationsWereMet()) +} + +// A session whose connection broke is ended: the locks on it are gone, a +// release of one asks nothing, and the next take opens a new session. +func TestTry_ABrokenSessionIsEnded(t *testing.T) { + s, mock := newMock(t) + ctx := context.Background() + mock.ExpectQuery(lockQ).WithArgs(int64(1)).WillReturnRows(granted(true)) + held, _, err := s.Try(ctx, ID(1)) + require.NoError(t, err) + + mock.ExpectQuery(lockQ).WithArgs(int64(2)).WillReturnError(driver.ErrBadConn) + _, _, err = s.Try(ctx, ID(2)) + require.ErrorIs(t, err, driver.ErrBadConn) + assert.Nil(t, s.conn, "the broken session was ended") + assert.Empty(t, s.held, "its locks went with it") + held() // no statement: the lock ended with the session + require.NoError(t, mock.ExpectationsWereMet()) +} diff --git a/internal/advisorylock/loops_realdb_integration_test.go b/internal/advisorylock/loops_realdb_integration_test.go new file mode 100644 index 000000000..06ce4a2b8 --- /dev/null +++ b/internal/advisorylock/loops_realdb_integration_test.go @@ -0,0 +1,73 @@ +//go:build integration + +package advisorylock_test + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/txn2/mcp-data-platform/internal/connlimit" + "github.com/txn2/mcp-data-platform/internal/dbobs" + "github.com/txn2/mcp-data-platform/internal/platform/levelalert" + "github.com/txn2/mcp-data-platform/internal/platform/storagecap" + "github.com/txn2/mcp-data-platform/internal/testdb" + "github.com/txn2/mcp-data-platform/internal/webhook/whalert" + "github.com/txn2/mcp-data-platform/pkg/connoauth" +) + +// TestRealDB_TheLoopsShareOneConnection holds, all at once and on a pool of +// the platform's minimum, the locks of the two loops v1.147.0 added (storage +// capacity and webhook alerts, through levelalert.Locked), two connlimit +// slots and a connoauth refresh lock, and serves a request while they are +// held: between them they hold one connection (#2169). +func TestRealDB_TheLoopsShareOneConnection(t *testing.T) { + db := testdb.New(t) + db.SetMaxOpenConns(dbobs.MinOpenConns) + baseline := db.Stats().InUse + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + release := make(chan struct{}) + var held, done sync.WaitGroup + for _, key := range []int64{storagecap.LockKey, whalert.LockKey} { + held.Add(1) + done.Go(func() { + err := levelalert.Locked(ctx, db, key, func(ctx context.Context) error { + held.Done() + <-release + var n int + return db.QueryRowContext(ctx, "SELECT count(*) FROM alert_conditions").Scan(&n) + }) + assert.NoError(t, err, "key %d", key) + }) + } + limiter := connlimit.New(db, nil) + var slots []*connlimit.Slot + for range 2 { + slot, _, err := limiter.Acquire(ctx, "api", "crm", 2) + require.NoError(t, err) + slots = append(slots, slot) + } + unlock, ok, err := connoauth.NewPostgresLocker(db).TryLock(ctx, connoauth.Key{Kind: connoauth.KindAPI, Name: "crm"}) + require.NoError(t, err) + require.True(t, ok) + held.Wait() + + assert.Equal(t, 1, db.Stats().InUse-baseline, "two loop locks, two slots and a refresh lock on one connection") + var answer int + require.NoError(t, db.QueryRowContext(ctx, "SELECT 1").Scan(&answer), "a request while they are held") + + close(release) + done.Wait() + for _, s := range slots { + s.Release() + } + unlock() + require.NoError(t, ctx.Err()) + assert.Equal(t, 0, db.Stats().InUse-baseline, "the session went back to the pool") +} diff --git a/internal/connlimit/connlimit.go b/internal/connlimit/connlimit.go index d4e481910..2348ab486 100644 --- a/internal/connlimit/connlimit.go +++ b/internal/connlimit/connlimit.go @@ -10,9 +10,9 @@ // export's page walk, a script's platform.call. // // A slot is a PostgreSQL session-level advisory lock, (connection, slot n), -// held on a pooled database connection for the length of the call, so the -// limit holds across replicas: an upstream that takes one request does not -// take three because the deployment runs three replicas. A call over the +// held on the process's lock session (internal/advisorylock) for the length +// of the call, so the limit holds across replicas: an upstream that takes one +// request does not take three because the deployment runs three replicas. A call over the // limit waits for a slot instead of failing, and the wait counts against the // call's own deadline; a call whose deadline passes while it waits fails // naming the limit and how long it waited. A deployment with no database @@ -22,7 +22,6 @@ package connlimit import ( "context" "database/sql" - "database/sql/driver" "errors" "fmt" "hash/fnv" @@ -30,6 +29,7 @@ import ( "sync/atomic" "time" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/pkg/observability" ) @@ -39,9 +39,6 @@ import ( const ( firstPoll = 20 * time.Millisecond maxPoll = 250 * time.Millisecond - // releaseTimeout bounds giving a slot back, which runs after the call's - // own context may have ended. - releaseTimeout = 5 * time.Second ) // keySpace is the first half of every slot's advisory-lock key. It is @@ -134,8 +131,7 @@ func (l *Limiter) Acquire(ctx context.Context, kind, connection string, limit in } // acquireShared takes a slot as an advisory lock, polling until one is free. -// A database connection is held only while a slot is: a waiting call holds -// none. +// A waiting call holds no database connection. func (l *Limiter) acquireShared(ctx context.Context, kind, connection string, limit int) (*Slot, error) { space := keySpace(kind, connection) // One request's wait for a slot, bounded by the request's own context: @@ -164,52 +160,26 @@ func pause(ctx context.Context, d time.Duration) error { } // tryShared takes the first free slot, or reports none free with a nil slot. +// Slots are held on the process's lock session, so however many calls are in +// flight they pin one database connection between them (#2169). func (l *Limiter) tryShared(ctx context.Context, space int32, limit int) (*Slot, error) { - conn, err := l.db.Conn(ctx) - if err != nil { - return nil, fmt.Errorf("reserving a database connection for the slot: %w", err) - } for n := int32(0); int(n) < limit; n++ { - var got bool - if err := conn.QueryRowContext(ctx, `SELECT pg_try_advisory_lock($1, $2)`, space, n).Scan(&got); err != nil { - discard(conn) - // A deadline reached during the query is the driver's cancel - // error; the call's own end is what the caller is told. + release, got, err := advisorylock.Try(ctx, l.db, advisorylock.Pair(space, n)) + if err != nil { + // A deadline reached during the take is the call's own end, and + // that is what the caller is told. if ctxErr := ctx.Err(); ctxErr != nil { return nil, ctxErr //nolint:wrapcheck // WaitError names it } return nil, fmt.Errorf("taking a slot: %w", err) } if got { - return &Slot{release: func() { unlockShared(conn, space, n) }}, nil + return &Slot{release: release}, nil } } - _ = conn.Close() return nil, nil //nolint:nilnil // no slot free is not a failure: the caller waits } -// unlockShared gives a slot back and returns its database connection to the -// pool. A connection whose unlock failed may still hold the lock, so it is -// closed rather than pooled: a pooled connection holding a slot would hold it -// until the pool closed it. -func unlockShared(conn *sql.Conn, space, n int32) { - ctx, cancel := context.WithTimeout(context.Background(), releaseTimeout) - defer cancel() - var released bool - if err := conn.QueryRowContext(ctx, `SELECT pg_advisory_unlock($1, $2)`, space, n).Scan(&released); err != nil || !released { - discard(conn) - return - } - _ = conn.Close() -} - -// discard closes conn and drops it from the pool, ending its session and with -// it any lock the session holds. -func discard(conn *sql.Conn) { - _ = conn.Raw(func(any) error { return driver.ErrBadConn }) - _ = conn.Close() -} - // acquireLocal takes a slot from this process's own count of the connection. func (l *Limiter) acquireLocal(ctx context.Context, kind, connection string, limit int) (*Slot, error) { key := fmt.Sprintf("%s\x00%s\x00%d", kind, connection, limit) diff --git a/internal/connlimit/connlimit_realdb_integration_test.go b/internal/connlimit/connlimit_realdb_integration_test.go index ea02a726c..137579510 100644 --- a/internal/connlimit/connlimit_realdb_integration_test.go +++ b/internal/connlimit/connlimit_realdb_integration_test.go @@ -45,8 +45,8 @@ func TestRealDB_TheLimitHoldsAcrossReplicas(t *testing.T) { } // TestRealDB_ASlotIsHeldOnlyWhileItIsHeld: a waiting call holds no database -// connection, a held slot frees on release, and a second slot is a second -// call in flight. +// connection, held slots share one, a held slot frees on release, and a +// second slot is a second call in flight. func TestRealDB_ASlotIsHeldOnlyWhileItIsHeld(t *testing.T) { db := testdb.New(t) a, b := New(db, nil), New(db, nil) @@ -66,8 +66,8 @@ func TestRealDB_ASlotIsHeldOnlyWhileItIsHeld(t *testing.T) { if _, _, err := b.Acquire(short, "api", "billing", 2); !errors.Is(err, context.DeadlineExceeded) { t.Fatalf("a third call took a slot of two: %v", err) } - if open := db.Stats().InUse - baseline; open != 2 { - t.Errorf("%d database connections in use; the two held slots hold one each and the waiter none", open) + if open := db.Stats().InUse - baseline; open != 1 { + t.Errorf("%d database connections in use; the two held slots share the process's lock session (#2169) and the waiter holds none", open) } first.Release() third, _, err := b.Acquire(ctx, "api", "billing", 2) diff --git a/internal/connlimit/shared_test.go b/internal/connlimit/shared_test.go index 931987463..92283f3fa 100644 --- a/internal/connlimit/shared_test.go +++ b/internal/connlimit/shared_test.go @@ -38,7 +38,7 @@ func TestShared_TakesTheFirstFreeSlotAndWaits(t *testing.T) { mock.ExpectQuery(tryLockQ).WithArgs(space, int32(1)).WillReturnRows(lockRow(false)) mock.ExpectQuery(tryLockQ).WithArgs(space, int32(0)).WillReturnRows(lockRow(false)) mock.ExpectQuery(tryLockQ).WithArgs(space, int32(1)).WillReturnRows(lockRow(true)) - mock.ExpectQuery(unlockQ).WithArgs(space, int32(1)).WillReturnRows(lockRow(true)) + mock.ExpectExec(unlockQ).WithArgs(space, int32(1)).WillReturnResult(sqlmock.NewResult(0, 0)) slot, waited, err := l.Acquire(context.Background(), "api", "crm", 2) if err != nil { @@ -83,7 +83,7 @@ func TestShared_DeadlineDuringTheQuery(t *testing.T) { } // A failed lock query fails the call rather than waiting forever, and an -// unlock that fails drops the database connection instead of pooling it. +// unlock that fails gives the slot back all the same. func TestShared_Failures(t *testing.T) { l, mock := sharedLimiter(t) down := errors.New("db down") @@ -96,21 +96,16 @@ func TestShared_Failures(t *testing.T) { t.Error(err) } - for _, unlock := range []func(*sqlmock.ExpectedQuery){ - func(q *sqlmock.ExpectedQuery) { q.WillReturnError(down) }, - func(q *sqlmock.ExpectedQuery) { q.WillReturnRows(lockRow(false)) }, - } { - l, mock := sharedLimiter(t) - mock.ExpectQuery(tryLockQ).WillReturnRows(lockRow(true)) - unlock(mock.ExpectQuery(unlockQ)) - slot, _, err := l.Acquire(context.Background(), "api", "crm", 1) - if err != nil { - t.Fatal(err) - } - slot.Release() - if err := mock.ExpectationsWereMet(); err != nil { - t.Error(err) - } + l, mock = sharedLimiter(t) + mock.ExpectQuery(tryLockQ).WillReturnRows(lockRow(true)) + mock.ExpectExec(unlockQ).WillReturnError(down) + slot, _, err := l.Acquire(context.Background(), "api", "crm", 1) + if err != nil { + t.Fatal(err) + } + slot.Release() + if err := mock.ExpectationsWereMet(); err != nil { + t.Error(err) } // No database connection to reserve: the call fails naming the limit. diff --git a/internal/dbobs/dbobs.go b/internal/dbobs/dbobs.go index f1ac698cd..995aff297 100644 --- a/internal/dbobs/dbobs.go +++ b/internal/dbobs/dbobs.go @@ -138,3 +138,20 @@ func isVectorSearch(query string) bool { } return false } + +// MinOpenConns is the smallest pool the platform runs on (#2169): one +// connection for the session every background lock shares, one for the +// statements of a locked pass, and two for the requests the replica serves +// meanwhile. +const MinOpenConns = 4 + +// CheckPoolSize refuses a database.max_open_conns too small for the platform +// to finish its own background work. Zero takes the default. +func CheckPoolSize(maxOpen int) error { + if maxOpen > 0 && maxOpen < MinOpenConns { + return fmt.Errorf("database.max_open_conns is %d; the platform needs at least %d: "+ + "one for the session its background locks share, one for a locked pass, and two for requests", + maxOpen, MinOpenConns) + } + return nil +} diff --git a/internal/dbobs/dbobs_test.go b/internal/dbobs/dbobs_test.go index 7018c29a9..e6862ad56 100644 --- a/internal/dbobs/dbobs_test.go +++ b/internal/dbobs/dbobs_test.go @@ -211,3 +211,17 @@ func TestOpen(t *testing.T) { require.NoError(t, err) require.NoError(t, db.Close()) } + +// #2169: a pool too small for the platform's own background work is refused +// at startup, naming the minimum; zero takes the default. +func TestCheckPoolSize(t *testing.T) { + for _, n := range []int{0, MinOpenConns, 25} { + if err := CheckPoolSize(n); err != nil { + t.Errorf("max_open_conns %d refused: %v", n, err) + } + } + err := CheckPoolSize(MinOpenConns - 1) + if err == nil || !strings.Contains(err.Error(), "database.max_open_conns is 3; the platform needs at least 4") { + t.Errorf("max_open_conns 3: %v", err) + } +} diff --git a/internal/httpserver/health/health.go b/internal/httpserver/health/health.go index 7f534c33b..fecaf6128 100644 --- a/internal/httpserver/health/health.go +++ b/internal/httpserver/health/health.go @@ -19,6 +19,13 @@ const ( // It is safe for concurrent use. type Checker struct { state atomic.Int32 + pool atomic.Pointer[PoolProbe] +} + +// WatchPool makes a starved database pool take the replica out of service +// while the process is otherwise ready (#2169). +func (c *Checker) WatchPool(p *PoolProbe) { + c.pool.Store(p) } // NewChecker creates a Checker in the Starting state. @@ -67,10 +74,14 @@ func (*Checker) LivenessHandler() http.HandlerFunc { } // ReadinessHandler returns an http.HandlerFunc that responds 200 when ready -// and 503 when starting or draining. +// and 503 when starting, draining, or its database pool is starved. // Use this for K8s readinessProbe (/readyz). func (c *Checker) ReadinessHandler() http.HandlerFunc { - return func(w http.ResponseWriter, _ *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + if c.IsReady() && c.pool.Load().Starved(r.Context()) { + writeJSON(w, http.StatusServiceUnavailable, healthResponse{Status: statusPoolStarved}) + return + } if c.IsReady() { writeJSON(w, http.StatusOK, healthResponse{Status: c.State()}) return diff --git a/internal/httpserver/health/pool.go b/internal/httpserver/health/pool.go new file mode 100644 index 000000000..eff259ab4 --- /dev/null +++ b/internal/httpserver/health/pool.go @@ -0,0 +1,83 @@ +package health + +import ( + "context" + "database/sql" + "log/slog" + "sync" + "time" +) + +// Pool starvation (#2169). A replica whose database pool hands out no +// connection serves nothing that reads the database, yet the process state +// alone kept /readyz at 200 while one did. A pool every connection of which +// is in use, and stays so, takes the replica out of service. A database that +// is down is not this: its pool opens no connections, and /readyz leaves an +// upstream outage to the dependency probes so it never takes every replica out +// at once. +const ( + // DefaultPoolWait is how long one probe waits for a connection. It is + // under the one second a readiness probe is given by default. + DefaultPoolWait = 500 * time.Millisecond + // DefaultPoolStarvedFor is how long the pool must go without handing one + // out before the replica reports not ready, so a busy pool that frees a + // connection now and then is not taken out of service. + DefaultPoolStarvedFor = 30 * time.Second + statusPoolStarved = "database_pool_starved" +) + +// PoolProbe reports whether a database pool can hand out a connection. +type PoolProbe struct { + db *sql.DB + wait time.Duration + starvedFor time.Duration + now func() time.Time + + mu sync.Mutex + since time.Time // when the pool was first found starved; zero while it is not +} + +// NewPoolProbe probes db, waiting wait for a connection and reporting it +// starved once it has handed none out for starvedFor. +func NewPoolProbe(db *sql.DB, wait, starvedFor time.Duration) *PoolProbe { + return &PoolProbe{db: db, wait: wait, starvedFor: starvedFor, now: time.Now} +} + +// Starved reports whether every connection of the pool has been in use, with +// none handed out on request, for at least starvedFor. +func (p *PoolProbe) Starved(ctx context.Context) bool { + if p == nil || p.db == nil { + return false + } + st := p.db.Stats() + if st.MaxOpenConnections == 0 || st.InUse < st.MaxOpenConnections || p.answers(ctx) { + p.mu.Lock() + p.since = time.Time{} + p.mu.Unlock() + return false + } + now := p.now() + p.mu.Lock() + defer p.mu.Unlock() + if p.since.IsZero() { + p.since = now + } + if now.Sub(p.since) < p.starvedFor { + return false + } + slog.WarnContext(ctx, "database pool starved: every connection in use and none handed out", + "in_use", st.InUse, "max_open_conns", st.MaxOpenConnections, "since", p.since) + return true +} + +// answers reports whether the pool hands out a connection within wait. +func (p *PoolProbe) answers(ctx context.Context) bool { + ctx, cancel := context.WithTimeout(ctx, p.wait) + defer cancel() + conn, err := p.db.Conn(ctx) + if err != nil { + return false + } + _ = conn.Close() + return true +} diff --git a/internal/httpserver/health/pool_test.go b/internal/httpserver/health/pool_test.go new file mode 100644 index 000000000..7c8f3330e --- /dev/null +++ b/internal/httpserver/health/pool_test.go @@ -0,0 +1,120 @@ +package health + +import ( + "context" + "database/sql" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +// starvedPool is a pool of one whose connection is taken. +func starvedPool(t *testing.T) (*sql.DB, *sql.Conn) { + t.Helper() + db, _, err := sqlmock.New() + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = db.Close() }) + db.SetMaxOpenConns(1) + conn, err := db.Conn(context.Background()) + if err != nil { + t.Fatal(err) + } + return db, conn +} + +func readyz(hc *Checker) (code int, status string) { + rec := httptest.NewRecorder() + hc.ReadinessHandler()(rec, httptest.NewRequestWithContext(context.Background(), http.MethodGet, "/readyz", http.NoBody)) + var body struct{ Status string } + _ = json.Unmarshal(rec.Body.Bytes(), &body) + return rec.Code, body.Status +} + +// #2169: a pool that hands out no connection for longer than starvedFor takes +// a ready replica out of service, and it comes back once a connection frees. +func TestReadiness_AStarvedPoolIsNotReady(t *testing.T) { + db, conn := starvedPool(t) + clock := time.Unix(1_000, 0) + probe := NewPoolProbe(db, 10*time.Millisecond, 30*time.Second) + probe.now = func() time.Time { return clock } + hc := NewChecker() + hc.SetReady() + hc.WatchPool(probe) + + if code, status := readyz(hc); code != http.StatusOK || status != stateNameReady { + t.Fatalf("first starved probe: %d %s; a pool is given starvedFor before it counts", code, status) + } + clock = clock.Add(29 * time.Second) + if code, _ := readyz(hc); code != http.StatusOK { + t.Fatalf("starved for 29s: %d", code) + } + clock = clock.Add(time.Second) + if code, status := readyz(hc); code != http.StatusServiceUnavailable || status != statusPoolStarved { + t.Fatalf("starved for 30s: %d %s", code, status) + } + + _ = conn.Close() + if code, _ := readyz(hc); code != http.StatusOK { + t.Fatalf("a freed connection: %d", code) + } + clock = clock.Add(time.Minute) + if _, err := db.Conn(context.Background()); err != nil { + t.Fatal(err) + } + if code, _ := readyz(hc); code != http.StatusOK { + t.Fatalf("starvation counts again from its own start: %d", code) + } +} + +// A pool with room, an unbounded pool and no pool at all are never starved; +// a starved pool does not make a draining replica report anything else. +func TestPoolProbe_NotStarved(t *testing.T) { + ctx := context.Background() + var nilProbe *PoolProbe + if nilProbe.Starved(ctx) || NewPoolProbe(nil, time.Millisecond, 0).Starved(ctx) { + t.Error("no pool is starved") + } + db, _, err := sqlmock.New() + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = db.Close() }) + if NewPoolProbe(db, time.Millisecond, 0).Starved(ctx) { + t.Error("an unbounded pool is starved") + } + db.SetMaxOpenConns(2) + if NewPoolProbe(db, time.Millisecond, 0).Starved(ctx) { + t.Error("a pool with room is starved") + } + + starved, _ := starvedPool(t) + hc := NewChecker() + hc.SetDraining() + hc.WatchPool(NewPoolProbe(starved, time.Millisecond, 0)) + if code, status := readyz(hc); code != http.StatusServiceUnavailable || status != stateNameDraining { + t.Errorf("draining with a starved pool: %d %s", code, status) + } +} + +// A pool every connection of which is in use, but which hands one out within +// the wait, is busy rather than starved. +func TestPoolProbe_ABusyPoolIsNotStarved(t *testing.T) { + db, conn := starvedPool(t) + probe := NewPoolProbe(db, 2*time.Second, 0) + freed := make(chan struct{}) + go func() { + defer close(freed) + time.Sleep(20 * time.Millisecond) + _ = conn.Close() + }() + if probe.Starved(context.Background()) { + t.Error("a pool that handed out a connection within the wait read as starved") + } + <-freed +} diff --git a/internal/httpserver/server.go b/internal/httpserver/server.go index 37d585435..c6d980dc3 100644 --- a/internal/httpserver/server.go +++ b/internal/httpserver/server.go @@ -171,6 +171,9 @@ func Serve(ctx context.Context, mcpServer *mcp.Server, p *platform.Platform, add mux := http.NewServeMux() hcfg := extractHTTPConfig(p) hc := health.NewChecker() + if p != nil && p.DB() != nil { + hc.WatchPool(health.NewPoolProbe(p.DB(), health.DefaultPoolWait, health.DefaultPoolStarvedFor)) + } if !hcfg.tlsEnabled { slog.WarnContext(ctx, "HTTP transport without TLS; credentials may be transmitted in plaintext") diff --git a/internal/maps/service.go b/internal/maps/service.go index a8863f911..89fbe8ba1 100644 --- a/internal/maps/service.go +++ b/internal/maps/service.go @@ -13,6 +13,7 @@ import ( "sync" "time" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" "github.com/txn2/mcp-data-platform/internal/logsan" "github.com/txn2/mcp-data-platform/internal/pmtiles" @@ -150,28 +151,14 @@ func (s *Service) poke() { } } -// advisoryLock takes the fetch lock on a session of its own, so the lock -// lives exactly as long as the pass. +// advisoryLock takes the fetch lock on the process's lock session; the pass +// runs on the pool (#2169). func (s *Service) advisoryLock(ctx context.Context) (unlock func(), ok bool, err error) { - conn, err := s.d.DB.Conn(ctx) + unlock, ok, err = advisorylock.Try(ctx, s.d.DB, advisorylock.ID(FetchLockKey)) if err != nil { - return nil, false, fmt.Errorf("maps: opening a lock session: %w", err) - } - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", FetchLockKey).Scan(&got); err != nil { - _ = conn.Close() return nil, false, fmt.Errorf("maps: taking the fetch lock: %w", err) } - if !got { - _ = conn.Close() - return nil, false, nil - } - return func() { - unlockCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second) - defer cancel() - _, _ = conn.ExecContext(unlockCtx, "SELECT pg_advisory_unlock($1)", FetchLockKey) - _ = conn.Close() - }, true, nil + return unlock, ok, nil } // Pass is one iteration of the fetch loop: under the fetch lock, it records diff --git a/internal/opranking/opranking.go b/internal/opranking/opranking.go index ce3168058..0437948be 100644 --- a/internal/opranking/opranking.go +++ b/internal/opranking/opranking.go @@ -76,6 +76,10 @@ const ScoreFloor = 0.45 // dominant while preserving that precision. const SemanticWeight = 0.6 +// unembeddedSemantic is the semantic term of a candidate with no vector: a +// cosine of zero mapped onto [0,1]. +const unembeddedSemantic = 0.5 + // Candidate is one rankable operation as this package sees it: an // opaque id the caller maps back, the text a query's tokens are matched // against, and the operation's embedding when one is indexed. @@ -169,7 +173,13 @@ func scoreOne(c Candidate, lexical bool, queryVec []float32, mode Mode) float64 if mode == ModeSemantic { return 0 } - return (1 - SemanticWeight) * lex + // A candidate not embedded yet is blended at a cosine of zero, the + // value every SQL ranker gives a row the vector arm cannot see + // (#2230): its lexical match then outranks every candidate that + // matches none of the query's tokens, as it does on every other + // surface. Blended at zero semantic, it fell below any near + // neighbor above 0.67. + return SemanticWeight*unembeddedSemantic + (1-SemanticWeight)*lex } // Map the cosine's [-1,1] onto [0,1] so the blend's two terms are on // one scale. diff --git a/internal/opranking/opranking_test.go b/internal/opranking/opranking_test.go index dd31e3a45..26554ad60 100644 --- a/internal/opranking/opranking_test.go +++ b/internal/opranking/opranking_test.go @@ -124,6 +124,24 @@ func TestScoreCreditsLexicalOnAnUnembeddedCandidate(t *testing.T) { } } +// #2230: an operation not embedded yet that contains every token of the +// query outranks a near neighbor that contains none, however near: it is +// blended at a cosine of zero, as every SQL ranker blends a row the vector +// arm cannot see. +func TestScoreAnUnembeddedMatchOutranksANearNeighbor(t *testing.T) { + cands := []Candidate{ + {ID: "neighbor", Fields: []string{"list invoices"}, Vector: []float32{0, 1, 0}}, + {ID: "match", Fields: []string{"list orders 2024"}}, + } + got := Score(cands, "orders 2024", []float32{0, 1, 0}, ModeHybrid) + if got[0].ID != "match" { + t.Fatalf("hybrid put %q first at %v; the unembedded token match (%v) must lead", got[0].ID, got[0].Score, got[1].Score) + } + if want := SemanticWeight*unembeddedSemantic + (1 - SemanticWeight); got[0].Score != want { + t.Errorf("the unembedded match scored %v; want %v, the SQL rankers' score for it", got[0].Score, want) + } +} + func TestScoreSemanticIgnoresAnUnembeddedCandidate(t *testing.T) { cands := []Candidate{{ID: "match", Fields: []string{"list orders"}}} got := Score(cands, "orders", []float32{0, 1, 0}, ModeSemantic) diff --git a/internal/platform/callrecord/outcome_realdb_integration_test.go b/internal/platform/callrecord/outcome_realdb_integration_test.go new file mode 100644 index 000000000..e04c51cf3 --- /dev/null +++ b/internal/platform/callrecord/outcome_realdb_integration_test.go @@ -0,0 +1,139 @@ +//go:build integration + +package callrecord + +import ( + "context" + "testing" + "time" + + sq "github.com/Masterminds/squirrel" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/txn2/mcp-data-platform/internal/testdb" +) + +// outcomeCatalogSize is #2231's catalog: the admin list took 36 seconds to +// filter about 95,000 records by outcome. +const outcomeCatalogSize = 100_000 + +// outcomeBound is how long one filtered page and its count may take. +const outcomeBound = time.Second + +// outcomeAttempts is how many times each is measured; the fastest counts. +const outcomeAttempts = 3 + +// seedOutcomeCatalog writes outcomeCatalogSize records: every seventeenth +// failed, pairs of reads over one target in one session (the newer supersedes +// the older), a memory record citing every seven-hundredth, and assets citing +// others. +func seedOutcomeCatalog(ctx context.Context, t *testing.T, store *PostgresStore) { + t.Helper() + _, err := store.db.ExecContext(ctx, ` + INSERT INTO call_records (event_id, kind, tool_name, connection, statement, targets, + user_id, session_id, success, created_at) + SELECT 'evt-' || g, 'sql', 'trino_query', 'wh', 'SELECT ' || (g / 2), + jsonb_build_array('trino:wh:t' || (g / 2)), 'u' || (g % 7), 's-' || (g / 20), + g % 17 <> 0, now() - make_interval(secs => g) + FROM generate_series(1, $1) AS g`, outcomeCatalogSize) + require.NoError(t, err) + _, err = store.db.ExecContext(ctx, ` + INSERT INTO memory_records (id, content, metadata) + SELECT 'mem-' || g, 'cites a call', jsonb_build_object('sources', jsonb_build_array('mcp:call:evt-' || (g * 700))) + FROM generate_series(1, $1 / 700) AS g`, outcomeCatalogSize) + require.NoError(t, err) + // Assets cite calls four ways: a save that named its call, an export that + // streamed one, a capture that swept a call in without naming it (cited + // set, not satisfied: the rule still decides), and a deleted asset. + _, err = store.db.ExecContext(ctx, ` + INSERT INTO portal_assets (id, owner_id, name, content_type, s3_bucket, s3_key, provenance, deleted_at) + SELECT 'asset-' || g || '-' || k.n, 'u0', 'cites a call', 'text/html', 'b', 'k' || g || k.n, + jsonb_build_object('captures', jsonb_build_array(jsonb_build_object( + 'tool', k.tool, 'explicit', k.explicit, + 'event_ids', jsonb_build_array('evt-' || (g * 900 + k.n)), + 'calls', jsonb_build_array(jsonb_build_object('event_id', 'evt-' || (g * 900 + k.n), 'cited', k.explicit))))), + CASE WHEN k.deleted THEN now() END + FROM generate_series(1, 60) AS g, + (VALUES (1, 'save_asset', true, false), (3, 'trino_export', true, false), + (5, 'save_asset', false, false), (7, 'save_asset', true, true)) AS k(n, tool, explicit, deleted)`) + require.NoError(t, err) + _, err = store.db.ExecContext(ctx, `ANALYZE call_records; ANALYZE memory_records; ANALYZE portal_assets`) + require.NoError(t, err) +} + +// unguardedOutcomes counts the catalog by outcome with the satisfied rule +// asked of every record, the read before #2231, so the guarded read is held to +// deciding every record the same way. +func unguardedOutcomes(ctx context.Context, t *testing.T, store *PostgresStore) map[string]int { + t.Helper() + inner := sq.Select(storedColumns...). + Column(satisfiedByCase("?")+" AS satisfied_by", callReferencePrefix()). + Column(supersededExpr). + Column(reuseCountExpr). + From("call_records r") + query, args, err := psq.Select("o.outcome", "COUNT(*)"). + FromSelect(outcomeOver(inner), "o").GroupBy("o.outcome").ToSql() + require.NoError(t, err) + rows, err := store.db.QueryContext(ctx, query, args...) + require.NoError(t, err) + defer func() { _ = rows.Close() }() + out := map[string]int{} + for rows.Next() { + var outcome string + var n int + require.NoError(t, rows.Scan(&outcome, &n)) + out[outcome] = n + } + require.NoError(t, rows.Err()) + return out +} + +// TestCallCatalogRealDBFiltersEachOutcomeWithinASecond is #2231: on a catalog +// of 100,000 records, a page of each outcome and its count answer within a +// second, for the whole catalog (the admin list) and for one caller's records +// (the portal's), and each outcome counts what the rule asked of every record +// counts. +func TestCallCatalogRealDBFiltersEachOutcomeWithinASecond(t *testing.T) { + ctx := context.Background() + store := NewPostgresStore(testdb.New(t), Config{}) + seedOutcomeCatalog(ctx, t, store) + want := unguardedOutcomes(ctx, t, store) + for _, outcome := range Outcomes { + require.Positive(t, want[outcome], "the seed holds no %s record", outcome) + } + + for _, scope := range []struct{ name, userID string }{{"admin", ""}, {"portal", "u0"}} { + for _, outcome := range Outcomes { + f := Filter{UserID: scope.userID, Outcome: outcome, Limit: 50} + // The best of three: this runs beside the rest of the real-database + // suite, and one sample that lands on another package's burst + // measures that package rather than this query. + var ( + page []Record + count int + took time.Duration + ) + for attempt := range outcomeAttempts { + start := time.Now() + var err error + page, err = store.List(ctx, f) + require.NoError(t, err) + count, err = store.Count(ctx, f) + require.NoError(t, err) + if d := time.Since(start); attempt == 0 || d < took { + took = d + } + } + t.Logf("%s %s: %d records, page and count in %s (best of %d)", scope.name, outcome, count, took, outcomeAttempts) + assert.Less(t, took, outcomeBound, "%s list filtered to %s", scope.name, outcome) + require.NotEmpty(t, page, "%s %s", scope.name, outcome) + for _, rec := range page { + assert.Equal(t, outcome, rec.Outcome) + } + if scope.userID == "" { + assert.Equal(t, want[outcome], count, "%s records counted", outcome) + } + } + } +} diff --git a/internal/platform/callrecord/postgres.go b/internal/platform/callrecord/postgres.go index 731bdf664..08345957b 100644 --- a/internal/platform/callrecord/postgres.go +++ b/internal/platform/callrecord/postgres.go @@ -153,9 +153,41 @@ func namedSourceExpr(eventID string) string { )` } +// citedSet is every event id an artifact names anywhere it could name a +// source: a memory record's sources and an asset capture's event_ids (#2231). +// It is not a second statement of the rule: every record satisfiedByCase finds +// satisfied is in it, so a read that must decide every record (a count) asks +// the rule only of the records in it and reads every other as unsatisfied, and +// a read of the satisfied records narrows to it first. The rule itself still +// decides. Collected once and hashed, it replaces two index probes per record, +// which on a catalog of 100,000 records was three seconds of every count. +// +// Each array is read only where it is one: containment, which the rule uses, +// never matches through a value that is not an array. The prefix is bound +// three times. +const citedSet = `SELECT substr(src.v, length(?) + 1) AS event_id FROM memory_records m + CROSS JOIN LATERAL jsonb_array_elements_text( + CASE WHEN jsonb_typeof(m.metadata->'sources') = 'array' THEN m.metadata->'sources' ELSE '[]'::jsonb END) src(v) + WHERE left(src.v, length(?)) = ? + UNION + SELECT ids.v FROM portal_assets a + CROSS JOIN LATERAL jsonb_array_elements( + CASE WHEN jsonb_typeof(a.provenance->'captures') = 'array' THEN a.provenance->'captures' ELSE '[]'::jsonb END) cap + CROSS JOIN LATERAL jsonb_array_elements_text( + CASE WHEN jsonb_typeof(cap->'event_ids') = 'array' THEN cap->'event_ids' ELSE '[]'::jsonb END) ids(v) + WHERE a.deleted_at IS NULL` + // satisfiedByExpr is the derived read's column: the rule above, named. var satisfiedByExpr = satisfiedByCase("?") + " AS satisfied_by" +// citedRule is the rule asked only of a record the joined citedSet names, and +// NULL for every other. It reads the joined row, which also keeps the planner +// from asking the rule of every record below the join. +var citedRule = "CASE WHEN cited.event_id IS NOT NULL THEN " + satisfiedByCase("?") + " END" + +// citedJoin joins citedSet as cited; the prefix is bound three times. +const citedJoin = "(" + citedSet + ") cited ON cited.event_id = r.event_id" + // supersededExpr answers whether the same session later ran a better version of // this call: same connection, same kind, same targets, and it succeeded. // @@ -169,7 +201,12 @@ var satisfiedByExpr = satisfiedByCase("?") + " AS satisfied_by" // mutation is not a better version of an earlier mutation, even against the // same resource (#1352). Approving a script twice is two decisions, and // inserting a row twice is two rows. -var supersededExpr = fmt.Sprintf(`EXISTS ( +var supersededExpr = supersededPredicate + " AS superseded" + +// supersededPredicate is the rule supersededExpr names. A count states it +// once more as a condition of the records it reads (#2231), where the planner +// can join it by hash rather than probe it per record. +var supersededPredicate = fmt.Sprintf(`EXISTS ( SELECT 1 FROM call_records l WHERE r.session_id <> '' AND l.session_id = r.session_id @@ -182,7 +219,7 @@ var supersededExpr = fmt.Sprintf(`EXISTS ( AND %s AND %s AND (l.created_at, l.event_id) > (r.created_at, r.event_id) -) AS superseded`, readShapedExpr("r"), readShapedExpr("l")) +)`, readShapedExpr("r"), readShapedExpr("l")) // readStatementPattern matches a statement that opens with a reading verb. It is // anchored at the start, past any opening parentheses a wrapped select carries, @@ -228,19 +265,105 @@ var outcomeExpr = fmt.Sprintf(`CASE ELSE '%s' END AS outcome`, OutcomeFailed, OutcomeSatisfied, OutcomeSuperseded, OutcomeRan) +// supersededLater is supersededPredicate for a read that decides every record +// at once (#2231): one pass over the reads that can take part, each group of +// one session, kind, connection and targets in (created_at, event_id) order, +// marking a read with a later successful read in its group. That is the rule's +// own condition, stated as an ordering: event_id is unique, so a call is never +// later than itself, only a read supersedes or is superseded, and a group's +// targets are non-empty and its session named whenever either call's are. +// Asked per record, the rule probed the session's calls once for each of +// 100,000 records; this sorts them once. +// +// The group is newest first, with the frame from its start to the row before, +// so the aggregate grows rather than being recomputed for every row: a session +// that calls one endpoint thousands of times costs a pass, not its square. +// Targets group by their text in byte order. Every writer stores them as an +// array of strings, for which equal text is equal jsonb, and comparing bytes +// is what keeps the sort from decoding each value. The joined row is sup, and +// sup.later is NULL for a call outside every group. +var supersededLater = fmt.Sprintf(`( + SELECT w.id, bool_or(w.success) OVER ( + PARTITION BY w.session_id, w.kind, w.connection, w.targets::text COLLATE "C" + ORDER BY w.created_at DESC, w.event_id DESC + ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS later + FROM call_records w + WHERE w.session_id <> '' AND jsonb_array_length(w.targets) > 0 AND %s +) sup ON sup.id = r.id`, readShapedExpr("w")) + +// supersededAtOnce is the rule's answer for the joined record: a read whose +// group holds a later successful read. A record the pass did not see is not a +// read in a session over targets, and is never superseded. +var supersededAtOnce = "COALESCE(sup.later, FALSE)" + +// outcomeCondition is outcomeExpr's branch for one outcome, as a condition on +// a record, for a count (#2231). Stated as the conditions the CASE reaches +// that outcome by, in its order, a count asks the satisfied rule only of a +// record citedSet names and asks the supersession rule only of a record that +// got past the branches before it. The branches are the CASE's, read from the +// same expressions. +// +// Supersession is read from supersededLater, one ordered pass, rather than +// probed per record. Written as the EXISTS in a WHERE clause it was a join the +// planner hashed on the session, kind, connection and targets, and the records +// with no session, or one session's thousands of calls to one endpoint, were +// then a single bucket compared pair by pair: a count of a catalog of 108,000 +// records, 103,000 with no session, ran for minutes. +func outcomeCondition(outcome string) sq.Sqlizer { + prefix := callReferencePrefix() + unsatisfied := sq.Expr("("+citedRule+") IS NULL", prefix) + switch outcome { + case OutcomeFailed: + return sq.Expr("NOT r.success") + case OutcomeSatisfied: + return sq.And{sq.Expr("r.success"), sq.Expr("("+citedRule+") IS NOT NULL", prefix)} + case OutcomeSuperseded: + return sq.And{sq.Expr("r.success"), unsatisfied, sq.Expr(supersededAtOnce)} + default: + return sq.And{sq.Expr("r.success"), unsatisfied, sq.Expr("NOT " + supersededAtOnce)} + } +} + // derived builds the record rows with their derived columns, before the outcome // is named or filtered. The capture reference prefix is bound rather than // spliced: the mcp: reference grammar has one owner (pkg/portal/knowledgepage) // and this reads it rather than restating it in SQL. +// +// A read of the satisfied records joins citedSet and asks the rule of the +// records it names (#2231): satisfied records are few, and found through the +// rule alone they cost a probe of every record in the catalog. Every other +// read asks the rule per record, so a page read newest first stops after a +// page of matches. func derived(f Filter) sq.SelectBuilder { - qb := sq.Select(storedColumns...). - Column(satisfiedByExpr, callReferencePrefix()). - Column(supersededExpr). - Column(reuseCountExpr). - From("call_records r") + prefix := callReferencePrefix() + qb := sq.Select(storedColumns...) + if facetOutcome(f) == OutcomeSatisfied { + qb = qb.Column(citedRule+" AS satisfied_by", prefix). + Column(supersededExpr). + Column(reuseCountExpr). + From("call_records r"). + Join(citedJoin, prefix, prefix, prefix) + } else { + qb = qb.Column(satisfiedByExpr, prefix). + Column(supersededExpr). + Column(reuseCountExpr). + From("call_records r") + } return applyFilters(qb, f) } +// facetOutcome is the outcome a filter narrows to, empty when none: its +// outcome, or satisfied for the review queue. +func facetOutcome(f Filter) string { + if f.PromotableOnly { + return OutcomeSatisfied + } + if ValidOutcome(f.Outcome) { + return f.Outcome + } + return "" +} + // withOutcome names the outcome over the derived rows. func withOutcome(f Filter) sq.SelectBuilder { return outcomeOver(derived(f)) } @@ -285,7 +408,20 @@ func applyFilters(qb sq.SelectBuilder, f Filter) sq.SelectBuilder { if f.PromotableOnly { qb = qb.Where(sq.Eq{"r.promoted_urn": "", "r.rejected_at": nil}) } - return qb + return successFilter(qb, f) +} + +// successFilter states, on the stored column, the part of an outcome facet +// the record's own success decides (#2231): a failed record is exactly one +// that did not succeed, and every other outcome is of one that did. The facet +// on the named outcome still decides; this keeps the derived columns from +// being computed for records it cannot match. +func successFilter(qb sq.SelectBuilder, f Filter) sq.SelectBuilder { + outcome := facetOutcome(f) + if outcome == "" { + return qb + } + return qb.Where(sq.Eq{"r.success": outcome != OutcomeFailed}) } // outcomeFilter applies the derived-outcome facets over the named rows. The @@ -314,6 +450,31 @@ func listQuery(f Filter) sq.SelectBuilder { return qb.OrderBy("o.created_at DESC", "o.event_id DESC") } +// noJIT turns JIT compilation off for a catalog read (#2231). The derived +// read's estimated cost is high enough that the planner compiles it, and the +// compile took a second and a half of every list and count on a catalog of +// 100,000 records, longer than the read. +const noJIT = "SET LOCAL jit = off" + +// withoutJIT runs fn in a read-only transaction under noJIT. +func (s *PostgresStore) withoutJIT(ctx context.Context, fn func(tx *sql.Tx) error) error { + tx, err := s.db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) + if err != nil { + return fmt.Errorf("opening the call record read: %w", err) + } + defer func() { _ = tx.Rollback() }() + if _, err := tx.ExecContext(ctx, noJIT); err != nil { + return fmt.Errorf("opening the call record read: %w", err) + } + if err := fn(tx); err != nil { + return err + } + if err := tx.Commit(); err != nil { + return fmt.Errorf("closing the call record read: %w", err) + } + return nil +} + // List returns records matching the filter, newest first. func (s *PostgresStore) List(ctx context.Context, f Filter) ([]Record, error) { qb := listQuery(f) @@ -328,39 +489,62 @@ func (s *PostgresStore) List(ctx context.Context, f Filter) ([]Record, error) { return nil, fmt.Errorf("building call record list query: %w", err) } - rows, err := s.db.QueryContext(ctx, query, args...) - if err != nil { - return nil, fmt.Errorf("querying call records: %w", err) - } - defer func() { _ = rows.Close() }() - records := make([]Record, 0, listCapacity(f.Limit)) - for rows.Next() { - rec, err := scanRecord(rows) + err = s.withoutJIT(ctx, func(tx *sql.Tx) error { + rows, err := tx.QueryContext(ctx, query, args...) if err != nil { - return nil, err + return fmt.Errorf("querying call records: %w", err) } - records = append(records, rec) - } - if err := rows.Err(); err != nil { - return nil, fmt.Errorf("iterating call records: %w", err) + defer func() { _ = rows.Close() }() + for rows.Next() { + rec, err := scanRecord(rows) + if err != nil { + return err + } + records = append(records, rec) + } + if err := rows.Err(); err != nil { + return fmt.Errorf("iterating call records: %w", err) + } + return nil + }) + if err != nil { + return nil, err } return records, nil } +// countQuery counts the records the filter matches. With an outcome facet it +// counts by outcomeCondition, over the records joined to citedSet; without +// one it names no outcome at all. +func countQuery(f Filter) sq.SelectBuilder { + qb := psq.Select("COUNT(*)").From("call_records r") + if outcome := facetOutcome(f); outcome != "" { + prefix := callReferencePrefix() + qb = qb.LeftJoin(citedJoin, prefix, prefix, prefix) + if outcome == OutcomeSuperseded || outcome == OutcomeRan { + qb = qb.LeftJoin(supersededLater) + } + qb = qb.Where(outcomeCondition(outcome)) + } + return applyFilters(qb, f) +} + // Count returns how many records match the filter, ignoring its paging. func (s *PostgresStore) Count(ctx context.Context, f Filter) (int, error) { - f.Limit, f.Offset = 0, 0 - inner := sq.Select("o.outcome").FromSelect(withOutcome(f), "o") - inner = outcomeFilter(inner, f) - - query, args, err := psq.Select("COUNT(*)").FromSelect(inner, "c").ToSql() + query, args, err := countQuery(f).ToSql() if err != nil { return 0, fmt.Errorf("building call record count query: %w", err) } var count int - if err := s.db.QueryRowContext(ctx, query, args...).Scan(&count); err != nil { - return 0, fmt.Errorf("counting call records: %w", err) + err = s.withoutJIT(ctx, func(tx *sql.Tx) error { + if err := tx.QueryRowContext(ctx, query, args...).Scan(&count); err != nil { + return fmt.Errorf("counting call records: %w", err) + } + return nil + }) + if err != nil { + return 0, err } return count, nil } diff --git a/internal/platform/callrecord/postgres_test.go b/internal/platform/callrecord/postgres_test.go index 1462762b7..5f8cdb088 100644 --- a/internal/platform/callrecord/postgres_test.go +++ b/internal/platform/callrecord/postgres_test.go @@ -76,10 +76,19 @@ func nullable(s string) any { return s } +// expectJITOff queues the read-only transaction a list or a count runs in, +// with JIT off (#2231). +func expectJITOff(mock sqlmock.Sqlmock) { + mock.ExpectBegin() + mock.ExpectExec("SET LOCAL jit = off").WillReturnResult(sqlmock.NewResult(0, 0)) +} + func TestListProjectsARecord(t *testing.T) { store, mock := newMock(t) + expectJITOff(mock) mock.ExpectQuery("FROM call_records"). WillReturnRows(recordRow(OutcomeSatisfied, SatisfiedByCapture, 2)) + mock.ExpectCommit() got, err := store.List(context.Background(), Filter{UserID: "u1", Limit: 10}) require.NoError(t, err) @@ -107,7 +116,9 @@ func TestListCarriesADecidedRecordsTimestamps(t *testing.T) { "asset", false, 0, OutcomeSatisfied, ) + expectJITOff(mock) mock.ExpectQuery("FROM call_records").WillReturnRows(row) + mock.ExpectCommit() got, err := store.List(context.Background(), Filter{}) require.NoError(t, err) require.Len(t, got, 1) @@ -123,9 +134,11 @@ func TestListScopesToTheCallerInSQL(t *testing.T) { store, mock := newMock(t) // The caller is a predicate inside the query, not a check after the read: // another caller's record must never be selected in the first place. + expectJITOff(mock) mock.ExpectQuery("FROM call_records"). WithArgs(sqlmock.AnyArg(), "u1"). WillReturnRows(sqlmock.NewRows(recordColumns)) + mock.ExpectCommit() _, err := store.List(context.Background(), Filter{UserID: "u1"}) require.NoError(t, err) @@ -133,8 +146,10 @@ func TestListScopesToTheCallerInSQL(t *testing.T) { func TestListAppliesEveryFacet(t *testing.T) { store, mock := newMock(t) + expectJITOff(mock) mock.ExpectQuery("FROM call_records"). WillReturnRows(sqlmock.NewRows(recordColumns)) + mock.ExpectCommit() _, err := store.List(context.Background(), Filter{ UserID: "u1", Kind: KindAPI, Connection: "acme", Outcome: OutcomeRan, @@ -148,8 +163,10 @@ func TestListReviewQueueOrdersByReuse(t *testing.T) { store, mock := newMock(t) // A query a stranger re-ran is better evidence than one its own author // vouched for, so the queue leads with reuse. + expectJITOff(mock) mock.ExpectQuery("ORDER BY o.reuse_count DESC"). WillReturnRows(recordRow(OutcomeSatisfied, SatisfiedByAsset, 3)) + mock.ExpectCommit() got, err := store.List(context.Background(), Filter{PromotableOnly: true}) require.NoError(t, err) @@ -158,7 +175,9 @@ func TestListReviewQueueOrdersByReuse(t *testing.T) { func TestListReportsAQueryFailure(t *testing.T) { store, mock := newMock(t) + expectJITOff(mock) mock.ExpectQuery("FROM call_records").WillReturnError(errors.New("db down")) + mock.ExpectRollback() _, err := store.List(context.Background(), Filter{}) require.Error(t, err) @@ -166,7 +185,9 @@ func TestListReportsAQueryFailure(t *testing.T) { func TestCountIgnoresPaging(t *testing.T) { store, mock := newMock(t) + expectJITOff(mock) mock.ExpectQuery("COUNT").WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(7)) + mock.ExpectCommit() got, err := store.Count(context.Background(), Filter{UserID: "u1", Limit: 5, Offset: 10}) require.NoError(t, err) @@ -400,3 +421,83 @@ func TestNormalizeTargetsSortsAndDeduplicates(t *testing.T) { // Verify the store satisfies the sql.DB-backed contract the wiring passes it as. var _ Store = (*PostgresStore)(nil) + +// TestCountByOutcomeStatesTheCasesBranch: a count filtered by outcome counts +// the records meeting the condition the outcome CASE reaches it by, over the +// cited join, and asks no outcome of an unfiltered count (#2231). +func TestCountByOutcomeStatesTheCasesBranch(t *testing.T) { + cases := map[string][]string{ + OutcomeFailed: {"NOT r.success", "r.success = $"}, + OutcomeSatisfied: {"cited.event_id IS NOT NULL THEN", ") IS NOT NULL"}, + OutcomeSuperseded: {") IS NULL", "COALESCE(sup.later, FALSE)", "PARTITION BY w.session_id"}, + OutcomeRan: {") IS NULL", "NOT COALESCE(sup.later, FALSE)", "PARTITION BY w.session_id"}, + } + for outcome, fragments := range cases { + query, _, err := countQuery(Filter{Outcome: outcome}).ToSql() + require.NoError(t, err) + assert.Contains(t, query, "LEFT JOIN (SELECT substr(src.v", outcome) + for _, fragment := range fragments { + assert.Contains(t, query, fragment, outcome) + } + assert.NotContains(t, query, "AS outcome", "a count names no outcome") + } + plain, _, err := countQuery(Filter{UserID: "u1"}).ToSql() + require.NoError(t, err) + assert.NotContains(t, plain, "cited.event_id", "an unfiltered count joins nothing") + queue, _, err := countQuery(Filter{PromotableOnly: true}).ToSql() + require.NoError(t, err) + assert.Contains(t, queue, ") IS NOT NULL", "the review queue counts satisfied records") +} + +// TestListOfSatisfiedJoinsTheCitedSet: a page of satisfied records reads the +// records an artifact names, and every other page asks the rule per record so +// it can stop at a page of matches (#2231). +func TestListOfSatisfiedJoinsTheCitedSet(t *testing.T) { + satisfied, _, err := listQuery(Filter{Outcome: OutcomeSatisfied}).ToSql() + require.NoError(t, err) + assert.Contains(t, satisfied, "JOIN (SELECT substr(src.v") + assert.Contains(t, satisfied, "r.success = $") + ran, _, err := listQuery(Filter{Outcome: OutcomeRan}).ToSql() + require.NoError(t, err) + assert.NotContains(t, ran, "cited.event_id") +} + +// TestCatalogReadFailures: each step of the read's transaction that fails is +// reported. +func TestCatalogReadFailures(t *testing.T) { + boom := errors.New("db down") + steps := map[string]func(sqlmock.Sqlmock){ + "begin": func(m sqlmock.Sqlmock) { m.ExpectBegin().WillReturnError(boom) }, + "settings": func(m sqlmock.Sqlmock) { + m.ExpectBegin() + m.ExpectExec("SET LOCAL jit").WillReturnError(boom) + m.ExpectRollback() + }, + "count": func(m sqlmock.Sqlmock) { + expectJITOff(m) + m.ExpectQuery("COUNT").WillReturnError(boom) + m.ExpectRollback() + }, + "commit": func(m sqlmock.Sqlmock) { + expectJITOff(m) + m.ExpectQuery("COUNT").WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) + m.ExpectCommit().WillReturnError(boom) + }, + } + for name, expect := range steps { + t.Run(name, func(t *testing.T) { + store, mock := newMock(t) + expect(mock) + _, err := store.Count(context.Background(), Filter{UserID: "u1"}) + require.ErrorIs(t, err, boom) + }) + } + t.Run("scan", func(t *testing.T) { + store, mock := newMock(t) + expectJITOff(mock) + mock.ExpectQuery("FROM call_records").WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("x")) + mock.ExpectRollback() + _, err := store.List(context.Background(), Filter{}) + require.Error(t, err) + }) +} diff --git a/internal/platform/callrecord/retention.go b/internal/platform/callrecord/retention.go index d37f7240e..1d5180144 100644 --- a/internal/platform/callrecord/retention.go +++ b/internal/platform/callrecord/retention.go @@ -9,7 +9,9 @@ import ( "github.com/lib/pq" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" + "github.com/txn2/mcp-data-platform/internal/logsan" "github.com/txn2/mcp-data-platform/internal/opsobs" "github.com/txn2/mcp-data-platform/pkg/script" ) @@ -63,10 +65,6 @@ const ( // subsystem's sweep never blocks another's. sweepLockKey = 4713210001 - // unlockTimeout bounds the advisory unlock after a sweep, so a shutdown - // cannot hang on releasing it. - unlockTimeout = 5 * time.Second - // sweepBatchSize bounds how many records one statement of the sweep // removes. It is the same bound the index queue's own retention purges // by: large enough that a steady-state sweep is one statement, small @@ -242,30 +240,16 @@ func (s *PostgresStore) Close() error { // deletes per tick. It returns bgloop.ErrSkipped when another replica held // the lock, and the error of a sweep that failed. func (s *PostgresStore) sweepTick(ctx context.Context) error { - conn, err := s.db.Conn(ctx) + release, acquired, err := advisorylock.Try(ctx, s.db, advisorylock.ID(sweepLockKey)) if err != nil { - slog.WarnContext(ctx, "call catalog: acquire connection for the retention lock", "error", err) - return fmt.Errorf("call catalog: retention lock connection: %w", err) - } - defer func() { _ = conn.Close() }() - - var acquired bool - if err := conn.QueryRowContext(ctx, - "SELECT pg_try_advisory_lock($1)", sweepLockKey).Scan(&acquired); err != nil { - slog.WarnContext(ctx, "call catalog: try retention lock", "error", err) + slog.WarnContext(ctx, "call catalog: try retention lock", "error", logsan.SanitizeForLog(err.Error())) return fmt.Errorf("call catalog: try retention lock: %w", err) } if !acquired { // Another replica is sweeping; this tick has nothing to do. return bgloop.ErrSkipped } - defer func() { - unlockCtx, cancel := context.WithTimeout(context.Background(), unlockTimeout) - defer cancel() - if _, err := conn.ExecContext(unlockCtx, "SELECT pg_advisory_unlock($1)", sweepLockKey); err != nil { - slog.WarnContext(ctx, "call catalog: release retention lock", "error", err) - } - }() + defer release() removed, err := s.Cleanup(ctx) if err != nil { diff --git a/internal/platform/capacity/capacity.go b/internal/platform/capacity/capacity.go index 5830f5f59..87bbf2dbd 100644 --- a/internal/platform/capacity/capacity.go +++ b/internal/platform/capacity/capacity.go @@ -32,6 +32,7 @@ import ( "sync" "time" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" "github.com/txn2/mcp-data-platform/internal/logsan" "github.com/txn2/mcp-data-platform/internal/objectobs" @@ -49,8 +50,6 @@ const ( // other maintenance lock (retention 4713210101-4713210105, the call // catalog 4713210001, maps 4713210301). scanLockKey int64 = 4713210401 - - unlockTimeout = 5 * time.Second ) // Sources is what the service reads. @@ -355,27 +354,16 @@ var errListedRecently = errors.New("capacity: listed recently") // recent for. const recentFraction = 0.9 -// locked runs fn while holding the listing's advisory lock on a dedicated -// connection, since an advisory lock belongs to the session that took it. +// locked runs fn while holding the listing's advisory lock on the process's +// lock session; fn runs on the pool (#2169). func (s *Service) locked(ctx context.Context, fn func(context.Context) error) (bool, error) { - conn, err := s.src.DB.Conn(ctx) + release, got, err := advisorylock.Try(ctx, s.src.DB, advisorylock.ID(scanLockKey)) if err != nil { - return false, fmt.Errorf("acquiring a connection for the lock: %w", err) - } - defer func() { _ = conn.Close() }() - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", scanLockKey).Scan(&got); err != nil { - return false, fmt.Errorf("taking the advisory lock: %w", err) + return false, err //nolint:wrapcheck // the lock session names the statement } if !got { return false, nil } - defer func() { - unlockCtx, cancel := context.WithTimeout(context.Background(), unlockTimeout) - defer cancel() - if _, err := conn.ExecContext(unlockCtx, "SELECT pg_advisory_unlock($1)", scanLockKey); err != nil { - slog.WarnContext(ctx, "capacity: advisory unlock failed", "error", logsan.SanitizeForLog(err.Error())) - } - }() + defer release() return true, fn(ctx) } diff --git a/internal/platform/capacity/capacity_test.go b/internal/platform/capacity/capacity_test.go index 15aa41bd5..c0deec3a0 100644 --- a/internal/platform/capacity/capacity_test.go +++ b/internal/platform/capacity/capacity_test.go @@ -261,7 +261,7 @@ func TestService_ScanFailures(t *testing.T) { require.NoError(t, mock.ExpectationsWereMet()) _ = db.Close() - require.ErrorContains(t, s.scan(context.Background()), "acquiring a connection") + require.ErrorContains(t, s.scan(context.Background()), "acquiring the lock session") } // TestService_AdministratorBudgetsOverrideTheEnvironment covers #2148: a diff --git a/internal/platform/catalogimport/runner.go b/internal/platform/catalogimport/runner.go index c3202c76f..ecd1be4a0 100644 --- a/internal/platform/catalogimport/runner.go +++ b/internal/platform/catalogimport/runner.go @@ -8,6 +8,7 @@ import ( "log/slog" "sync" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/logsan" ) @@ -129,22 +130,16 @@ func (rn *Runner) Start(ctx context.Context, url, token, by string) (Run, error) if err != nil { return Run{}, fmt.Errorf("opening DataHub at %s: %w", url, err) } - conn, err := rn.db.Conn(ctx) + release, got, err := advisorylock.Try(ctx, rn.db, advisorylock.ID(LockKey)) if err != nil { - return Run{}, fmt.Errorf("taking a connection for the import's lock: %w", err) - } - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", LockKey).Scan(&got); err != nil { - _ = conn.Close() return Run{}, fmt.Errorf("taking the import's lock: %w", err) } if !got { - _ = conn.Close() return Run{}, ErrRunning } run, err := rn.store.begin(ctx, url, by) if err != nil { - release(conn) + release() return Run{}, err } rn.mu.Lock() @@ -153,7 +148,7 @@ func (rn *Runner) Start(ctx context.Context, url, token, by string) (Run, error) rn.mu.Unlock() go func() { defer rn.wg.Done() - defer release(conn) + defer release() rn.execute(runCtx, run.ID, src) }() return run, nil @@ -176,12 +171,6 @@ func (rn *Runner) execute(ctx context.Context, id string, src Source) { } } -// release lets go of the lock and its connection. -func release(conn *sql.Conn) { - _, _ = conn.ExecContext(context.Background(), "SELECT pg_advisory_unlock($1)", LockKey) - _ = conn.Close() -} - // Runs lists the latest runs, newest first, saying which is under way. func (rn *Runner) Runs(ctx context.Context, limit int) ([]Run, error) { running, err := rn.locked(ctx) @@ -193,19 +182,11 @@ func (rn *Runner) Runs(ctx context.Context, limit int) ([]Run, error) { // locked reports whether some replica holds the import's lock. func (rn *Runner) locked(ctx context.Context) (bool, error) { - conn, err := rn.db.Conn(ctx) + held, err := advisorylock.For(rn.db).Held(ctx, advisorylock.ID(LockKey)) if err != nil { - return false, fmt.Errorf("taking a connection to read the import's lock: %w", err) - } - defer func() { _ = conn.Close() }() - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", LockKey).Scan(&got); err != nil { return false, fmt.Errorf("reading the import's lock: %w", err) } - if got { - _, _ = conn.ExecContext(ctx, "SELECT pg_advisory_unlock($1)", LockKey) - } - return !got, nil + return held, nil } // Configured is the address of the DataHub the configuration names, or "". diff --git a/internal/platform/catalogscan/loop.go b/internal/platform/catalogscan/loop.go index a3286a978..2bdeed1e2 100644 --- a/internal/platform/catalogscan/loop.go +++ b/internal/platform/catalogscan/loop.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" "github.com/txn2/mcp-data-platform/internal/logsan" ) @@ -21,9 +22,6 @@ const LockKey int64 = 4713210201 // it a scan starts. const pollInterval = time.Minute -// unlockTimeout bounds the release of the lock after a scan. -const unlockTimeout = 5 * time.Second - // Loop runs a scan whenever the configured interval has passed since the // last one any replica started, and whenever asked to. type Loop struct { @@ -141,8 +139,8 @@ func (l *Loop) runOnce(ctx context.Context) error { // requested; no row means neither has happened. const scanDue = `SELECT started_at, requested_at FROM catalog_scan_state WHERE id` -// lockedScan takes the lock on a dedicated connection, since an advisory lock -// belongs to the session that took it, and scans when due. It returns +// lockedScan takes the lock on the process's lock session and scans when +// due; the scan's own queries run on the pool (#2169). It returns // bgloop.ErrSkipped when another replica holds the lock, and ran is false // when no scan was due. // @@ -150,31 +148,20 @@ const scanDue = `SELECT started_at, requested_at FROM catalog_scan_state WHERE i // replica that asked was refused the lock, and would otherwise wait for its // next poll to look again (#2218). func (l *Loop) lockedScan(ctx context.Context) (ran bool, err error) { - conn, err := l.db.Conn(ctx) + release, got, err := advisorylock.Try(ctx, l.db, advisorylock.ID(LockKey)) if err != nil { - return false, fmt.Errorf("acquiring a connection for the lock: %w", err) - } - defer func() { _ = conn.Close() }() - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", LockKey).Scan(&got); err != nil { - return false, fmt.Errorf("taking the advisory lock: %w", err) + return false, err //nolint:wrapcheck // the lock session names the statement } if !got { return false, bgloop.ErrSkipped } - defer func() { - unlockCtx, cancel := context.WithTimeout(context.Background(), unlockTimeout) - defer cancel() - if _, uerr := conn.ExecContext(unlockCtx, "SELECT pg_advisory_unlock($1)", LockKey); uerr != nil { - slog.WarnContext(ctx, "catalog scan: advisory unlock failed", "error", logsan.SanitizeForLog(uerr.Error())) - } - }() + defer release() for { - due, err := l.due(ctx, conn) + due, err := l.due(ctx) if err != nil || !due { return ran, err } - if _, err := conn.ExecContext(ctx, recordStart); err != nil { + if _, err := l.db.ExecContext(ctx, recordStart); err != nil { return ran, fmt.Errorf("recording the scan's start: %w", err) } if _, err := l.scanner.Scan(ctx); err != nil { @@ -189,13 +176,13 @@ func (l *Loop) lockedScan(ctx context.Context) (ran bool, err error) { // started. // The times are read under the lock, so two replicas cannot both find the // same scan due. -func (l *Loop) due(ctx context.Context, conn *sql.Conn) (bool, error) { +func (l *Loop) due(ctx context.Context) (bool, error) { set, err := l.settings.Get(ctx) if err != nil { return false, fmt.Errorf("reading catalog settings: %w", err) } var last, requested sql.NullTime - err = conn.QueryRowContext(ctx, scanDue).Scan(&last, &requested) + err = l.db.QueryRowContext(ctx, scanDue).Scan(&last, &requested) if err != nil && !errors.Is(err, sql.ErrNoRows) { return false, fmt.Errorf("reading the last scan: %w", err) } diff --git a/internal/platform/knowledgebuiltin/pages/asset-references-and-the-refresh-loop.md b/internal/platform/knowledgebuiltin/pages/asset-references-and-the-refresh-loop.md index 68a339878..15e82204f 100644 --- a/internal/platform/knowledgebuiltin/pages/asset-references-and-the-refresh-loop.md +++ b/internal/platform/knowledgebuiltin/pages/asset-references-and-the-refresh-loop.md @@ -48,7 +48,11 @@ list. Two forms go in it, and they are not interchangeable: The list is the whole declaration. Omitting it leaves the asset's references alone, sending a list replaces them, and sending an empty list removes them -all. At most 20 per asset unless the deployment sets its own cap; the +all. A write that changes the content and the list together grants the newly +listed files before the new version exists, so the version's tile and its +first reader see them, and drops the ones no longer listed once the content is +stored; a write whose content cannot be stored leaves the references as they +were. At most 20 per asset unless the deployment sets its own cap; the `references` field's `maxItems` in the save_asset and manage_asset schemas states this deployment's number. A save above it is refused with the number you declared. diff --git a/internal/platform/levelalert/levelalert.go b/internal/platform/levelalert/levelalert.go index 82fc2fb19..a8e3015ad 100644 --- a/internal/platform/levelalert/levelalert.go +++ b/internal/platform/levelalert/levelalert.go @@ -17,13 +17,12 @@ import ( "database/sql" "errors" "fmt" - "log/slog" "strconv" "strings" "time" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" - "github.com/txn2/mcp-data-platform/internal/logsan" "github.com/txn2/mcp-data-platform/pkg/notification" ) @@ -224,33 +223,19 @@ func (s *PostgresStore) Delete(ctx context.Context, key string) error { return nil } -// unlockTimeout bounds the unlock after a locked pass, which runs on a context -// that may already be done. -const unlockTimeout = 5 * time.Second - -// Locked runs fn while holding the session advisory lock key on a dedicated -// connection, so one replica evaluates a family at a time. It returns -// bgloop.ErrSkipped when another replica holds the lock. +// Locked runs fn while holding the advisory lock key on the process's lock +// session, so one replica evaluates a family at a time. fn runs on the pool, +// never on the lock's session (#2169). It returns bgloop.ErrSkipped when +// another replica holds the lock. func Locked(ctx context.Context, db *sql.DB, key int64, fn func(ctx context.Context) error) error { - conn, err := db.Conn(ctx) + release, got, err := advisorylock.Try(ctx, db, advisorylock.ID(key)) if err != nil { - return fmt.Errorf("acquiring a connection for the lock: %w", err) - } - defer func() { _ = conn.Close() }() - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", key).Scan(&got); err != nil { - return fmt.Errorf("taking the advisory lock: %w", err) + return err //nolint:wrapcheck // the lock session names the statement } if !got { return bgloop.ErrSkipped } - defer func() { - unlockCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), unlockTimeout) - defer cancel() - if _, uerr := conn.ExecContext(unlockCtx, "SELECT pg_advisory_unlock($1)", key); uerr != nil { - slog.WarnContext(ctx, "alert evaluation: advisory unlock failed", "error", logsan.SanitizeForLog(uerr.Error())) - } - }() + defer release() return fn(ctx) } diff --git a/internal/platform/resourcereclass/resourcereclass.go b/internal/platform/resourcereclass/resourcereclass.go index ff61c912b..bb4681ab5 100644 --- a/internal/platform/resourcereclass/resourcereclass.go +++ b/internal/platform/resourcereclass/resourcereclass.go @@ -14,6 +14,7 @@ import ( "github.com/lib/pq" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/indexpolicy" "github.com/txn2/mcp-data-platform/pkg/indexjobs" "github.com/txn2/mcp-data-platform/pkg/resource" @@ -76,32 +77,25 @@ type reclassRow struct { // whole walk and answers ErrReclassifyRunning when another holds it. func (r *Reclassifier) Run(ctx context.Context) (ReclassifyResult, error) { var out ReclassifyResult - conn, err := r.db.Conn(ctx) + release, got, err := advisorylock.Try(ctx, r.db, advisorylock.ID(reclassifyLock)) if err != nil { - return out, fmt.Errorf("resourceindex: reclassify connection: %w", err) - } - defer conn.Close() //nolint:errcheck // returning the connection to the pool - var got bool - if err := conn.QueryRowContext(ctx, `SELECT pg_try_advisory_lock($1)`, reclassifyLock).Scan(&got); err != nil { return out, fmt.Errorf("resourceindex: reclassify lock: %w", err) } if !got { return out, ErrReclassifyRunning } - defer func() { - _, _ = conn.ExecContext(context.WithoutCancel(ctx), `SELECT pg_advisory_unlock($1)`, reclassifyLock) - }() + defer release() cursor := "" for { - rows, err := r.batch(ctx, conn, cursor) + rows, err := r.batch(ctx, cursor) if err != nil { return out, err } if len(rows) == 0 { return out, nil } - if err := r.apply(ctx, conn, rows, &out); err != nil { + if err := r.apply(ctx, rows, &out); err != nil { return out, err } cursor = rows[len(rows)-1].id @@ -111,8 +105,8 @@ func (r *Reclassifier) Run(ctx context.Context) (ReclassifyResult, error) { } } -func (*Reclassifier) batch(ctx context.Context, conn *sql.Conn, cursor string) ([]reclassRow, error) { - rows, err := conn.QueryContext(ctx, `SELECT id, index_policy, index_policy_explicit, path, mime_type, +func (r *Reclassifier) batch(ctx context.Context, cursor string) ([]reclassRow, error) { + rows, err := r.db.QueryContext(ctx, `SELECT id, index_policy, index_policy_explicit, path, mime_type, size_bytes, scope, COALESCE(scope_id, ''), uploader_sub, content_text <> '' FROM resources WHERE id > $1 ORDER BY id LIMIT 500`, cursor) if err != nil { @@ -169,13 +163,13 @@ func (r *Reclassifier) plan(rows []reclassRow, out *ReclassifyResult) reclassPla // apply rewrites one batch: each changed row under its new policy, and the // kept text of every row whose policy reads none. -func (r *Reclassifier) apply(ctx context.Context, conn *sql.Conn, rows []reclassRow, out *ReclassifyResult) error { +func (r *Reclassifier) apply(ctx context.Context, rows []reclassRow, out *ReclassifyResult) error { p := r.plan(rows, out) - if err := r.move(ctx, conn, p.changed, out); err != nil { + if err := r.move(ctx, p.changed, out); err != nil { return err } if len(p.stale) > 0 { - if _, err := conn.ExecContext(ctx, `UPDATE resources SET content_text = '' WHERE id = ANY($1)`, + if _, err := r.db.ExecContext(ctx, `UPDATE resources SET content_text = '' WHERE id = ANY($1)`, pq.Array(p.stale)); err != nil { return fmt.Errorf("resourceindex: reclassify clear: %w", err) } @@ -189,10 +183,10 @@ func (r *Reclassifier) apply(ctx context.Context, conn *sql.Conn, rows []reclass // move writes each changed row under its new policy, dropping its vector and // kept text, and enqueues the ones still indexed. -func (r *Reclassifier) move(ctx context.Context, conn *sql.Conn, changed map[indexpolicy.Policy][]string, out *ReclassifyResult) error { +func (r *Reclassifier) move(ctx context.Context, changed map[indexpolicy.Policy][]string, out *ReclassifyResult) error { for policy, ids := range changed { // A writer's choice made after the batch was read is left alone. - res, err := conn.ExecContext(ctx, `UPDATE resources SET index_policy = $1, + res, err := r.db.ExecContext(ctx, `UPDATE resources SET index_policy = $1, content_text = '', content_indexed_at = NULL, embedding = NULL, embedding_model = '', embedding_text_hash = NULL WHERE id = ANY($2) AND NOT index_policy_explicit`, string(policy), pq.Array(ids)) diff --git a/internal/platform/retention/retention.go b/internal/platform/retention/retention.go index e3f7eed65..4cc14c83d 100644 --- a/internal/platform/retention/retention.go +++ b/internal/platform/retention/retention.go @@ -22,6 +22,7 @@ import ( "sync" "time" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" "github.com/txn2/mcp-data-platform/internal/logsan" ) @@ -51,10 +52,6 @@ func Days(configured, def int) int { } } -// unlockTimeout bounds the advisory unlock after a sweep, so a shutdown -// cannot hang on releasing it. -const unlockTimeout = 5 * time.Second - // Sweep is one removal the loop runs. LockKey is its advisory lock, distinct // from every other maintenance lock in the platform. Run reports how many // rows it removed. @@ -152,29 +149,18 @@ func (l *Loop) RunOnce(ctx context.Context) error { return nil } -// runLocked runs one sweep while holding its advisory lock on a dedicated -// connection, since an advisory lock belongs to the session that took it. -// ran is false when another replica holds the lock. +// runLocked runs one sweep while holding its advisory lock on the process's +// lock session; the sweep runs on the pool (#2169). ran is false when another +// replica holds the lock. func (l *Loop) runLocked(ctx context.Context, s Sweep) (removed int64, ran bool, err error) { - conn, err := l.db.Conn(ctx) + release, got, err := advisorylock.Try(ctx, l.db, advisorylock.ID(s.LockKey)) if err != nil { - return 0, false, fmt.Errorf("acquiring a connection for the lock: %w", err) - } - defer func() { _ = conn.Close() }() - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", s.LockKey).Scan(&got); err != nil { - return 0, false, fmt.Errorf("taking the advisory lock: %w", err) + return 0, false, err //nolint:wrapcheck // the lock session names the statement } if !got { return 0, false, nil } - defer func() { - unlockCtx, cancel := context.WithTimeout(context.Background(), unlockTimeout) - defer cancel() - if _, uerr := conn.ExecContext(unlockCtx, "SELECT pg_advisory_unlock($1)", s.LockKey); uerr != nil { - slog.WarnContext(ctx, "retention: advisory unlock failed", "sweep", s.Name, "error", logsan.SanitizeForLog(uerr.Error())) - } - }() + defer release() removed, err = s.Run(ctx) return removed, true, err } diff --git a/internal/platform/retention/retention_test.go b/internal/platform/retention/retention_test.go index 18c28feb5..f9dbb0bf2 100644 --- a/internal/platform/retention/retention_test.go +++ b/internal/platform/retention/retention_test.go @@ -50,12 +50,16 @@ func TestRunOnce(t *testing.T) { mock.ExpectQuery(lockQ).WithArgs(int64(1)).WillReturnRows(sqlmock.NewRows([]string{"l"}).AddRow(true)) mock.ExpectExec(unlockQ).WithArgs(int64(1)).WillReturnResult(sqlmock.NewResult(0, 0)) mock.ExpectQuery(lockQ).WithArgs(int64(2)).WillReturnRows(sqlmock.NewRows([]string{"l"}).AddRow(false)) + mock.ExpectQuery(lockQ).WithArgs(int64(4)).WillReturnError(errors.New("down")) mock.ExpectQuery(lockQ).WithArgs(int64(3)).WillReturnRows(sqlmock.NewRows([]string{"l"}).AddRow(true)) + // An unlock that failed ends the lock session, so it comes last: the + // mock's one connection goes with it. mock.ExpectExec(unlockQ).WithArgs(int64(3)).WillReturnError(errors.New("gone")) - mock.ExpectQuery(lockQ).WithArgs(int64(4)).WillReturnError(errors.New("down")) - New(db, 0, sweep("first", 1, nil), sweep("held", 2, nil), sweep("failing", 3, errors.New("boom")), sweep("unlockable", 4, nil)). + err = New(db, 0, sweep("first", 1, nil), sweep("held", 2, nil), sweep("unlockable", 4, nil), sweep("failing", 3, errors.New("boom"))). RunOnce(context.Background()) + require.ErrorContains(t, err, "boom", "a failing sweep is reported") + require.ErrorContains(t, err, "down", "a lock that could not be taken is reported") assert.Equal(t, []string{"first", "failing"}, ran) assert.NoError(t, mock.ExpectationsWereMet()) diff --git a/internal/platform/storagecap/forecast.go b/internal/platform/storagecap/forecast.go index 3baa99d1a..36b0545c3 100644 --- a/internal/platform/storagecap/forecast.go +++ b/internal/platform/storagecap/forecast.go @@ -11,14 +11,17 @@ const ( longWindow = 30 * 24 * time.Hour day = 24 * time.Hour // minSpan7d and minSpan30d are the shortest stretch of history each rate - // is fitted over (#2201). A new install's first hours are setup, not - // growth: migrations, the built-in pages and their embeddings, the first - // catalog scan. An hour of that read as +112 MB/day, four times the whole - // database. A day of history is the least a weekly rate is read from, and - // a week the least a monthly one is, so the 30-day rate never repeats the - // 7-day one over the same few hours. + // is fitted over (#2201): a day for a weekly rate, and two weeks for a + // monthly one, so the 30-day rate is read from at least twice the history + // the 7-day rate is and never repeats it over the same days (#2203). minSpan7d = day - minSpan30d = 7 * day + minSpan30d = 14 * day + // settle is how much of a store's history is left out of every fit from + // its first sample (#2203). A new install's first hours are setup, not + // growth: migrations, the built-in pages and their embeddings, seeding, + // the first catalog scan. Fitted, they read as +87 MB/day for a database + // of 28 MB that had stopped growing. + settle = day // flatRate is the largest slope read as no growth, in bytes per day: a // store holding one size gives a slope of rounding error, never 0. flatRate = 1.0 @@ -62,16 +65,22 @@ type Forecast struct { // Project fits the store's growth over its history and, with its capacity, // when it fills. points are in time order; the last is the current reading. -func Project(points []Point, now time.Time) Forecast { +// born is when the store's history began, or zero when it began before the +// history kept: a store's first day is left out of every fit. +func Project(points []Point, now, born time.Time) Forecast { + from, wait := time.Time{}, time.Duration(0) + if !born.IsZero() { + from, wait = born.Add(settle), settle + } f := Forecast{ - Rate7dMinHistoryHours: minSpan7d.Hours(), - Rate30dMinHistoryHours: minSpan30d.Hours(), + Rate7dMinHistoryHours: (wait + minSpan7d).Hours(), + Rate30dMinHistoryHours: (wait + minSpan30d).Hours(), } if len(points) > 1 { f.HistoryHours = points[len(points)-1].At.Sub(points[0].At).Hours() } - f.Rate7d = rateOver(points, now.Add(-shortWindow), minSpan7d) - f.Rate30d = rateOver(points, now.Add(-longWindow), minSpan30d) + f.Rate7d = rateOver(points, latest(now.Add(-shortWindow), from), minSpan7d) + f.Rate30d = rateOver(points, latest(now.Add(-longWindow), from), minSpan30d) rate, used := slower(f.Rate7d, f.Rate30d) if rate == nil || len(points) == 0 { return f @@ -93,6 +102,14 @@ func Project(points []Point, now time.Time) Forecast { return f } +// latest is the later of two times. +func latest(a, b time.Time) time.Time { + if b.After(a) { + return b + } + return a +} + // slower is the smaller of the growing rates and which it is; nil when // neither grows. func slower(r7, r30 *float64) (rate *float64, name string) { diff --git a/internal/platform/storagecap/forecast_test.go b/internal/platform/storagecap/forecast_test.go index 5fa1c35a1..13f0c671f 100644 --- a/internal/platform/storagecap/forecast_test.go +++ b/internal/platform/storagecap/forecast_test.go @@ -32,7 +32,7 @@ func TestProjectMatchesTheLinearAnswer(t *testing.T) { total = int64(1 << 40) ) points := linear(30, interval, 100<<30, perDay, total) - f := Project(points, now) + f := Project(points, now, time.Time{}) require.NotNil(t, f.ExhaustionAt) last := points[len(points)-1] want := now.Add(time.Duration(float64(total-last.Used) / float64(perDay) * float64(day))) @@ -55,7 +55,7 @@ func TestProjectUsesTheSlowerRate(t *testing.T) { slow[i].Used += int64(float64(9<<30) * (7 - age.Hours()/24)) } } - f := Project(slow, now) + f := Project(slow, now, time.Time{}) require.NotNil(t, f.Rate7d) require.NotNil(t, f.Rate30d) assert.Less(t, *f.Rate30d, *f.Rate7d) @@ -63,20 +63,20 @@ func TestProjectUsesTheSlowerRate(t *testing.T) { // Only a week of history: the 7-day rate is all there is. week := linear(6, time.Hour, 0, 1<<30, 1<<40) - f = Project(week, now) + f = Project(week, now, time.Time{}) assert.Equal(t, "7d", f.RateUsed) } func TestProjectEdges(t *testing.T) { - empty := Forecast{Rate7dMinHistoryHours: 24, Rate30dMinHistoryHours: 168} - assert.Equal(t, empty, Project(nil, now)) + empty := Forecast{Rate7dMinHistoryHours: 24, Rate30dMinHistoryHours: 336} + assert.Equal(t, empty, Project(nil, now, time.Time{})) single := []Point{{At: now, Used: 1, Total: new(int64(10))}} - assert.Equal(t, empty, Project(single, now), "one sample has no rate") + assert.Equal(t, empty, Project(single, now, time.Time{}), "one sample has no rate") short := []Point{{At: now.Add(-time.Minute), Used: 1}, {At: now, Used: 2}} - assert.Nil(t, Project(short, now).Rate7d, "a minute of history is too short to fit") + assert.Nil(t, Project(short, now, time.Time{}).Rate7d, "a minute of history is too short to fit") shrinking := linear(10, time.Hour, 1<<40, -(1 << 30), 1<<41) - f := Project(shrinking, now) + f := Project(shrinking, now, time.Time{}) require.NotNil(t, f.Rate7d) assert.Negative(t, *f.Rate7d) assert.Nil(t, f.ExhaustionAt, "a store that is not growing does not fill") @@ -86,12 +86,12 @@ func TestProjectEdges(t *testing.T) { for i := range noCapacity { noCapacity[i].Total = nil } - f = Project(noCapacity, now) + f = Project(noCapacity, now, time.Time{}) assert.NotEmpty(t, f.RateUsed) assert.Nil(t, f.DaysLeft, "with no capacity there is no date") full := linear(10, time.Hour, 1<<40, 1<<30, 1<<30) - f = Project(full, now) + f = Project(full, now, time.Time{}) require.NotNil(t, f.DaysLeft) assert.Zero(t, *f.DaysLeft, "a store past its capacity has no days left") @@ -103,7 +103,7 @@ func TestProjectEdges(t *testing.T) { // TestProjectWaitsForEnoughHistory is #2201's first finding: a new install's // setup burst over its first hour and a half is no daily rate, and the 30-day -// rate waits for a week so it never repeats the 7-day one. +// rate waits for two weeks so it never repeats the 7-day one (#2203). func TestProjectWaitsForEnoughHistory(t *testing.T) { // The samples #2201 was reported from: 16 MB to 28 MB in 1h42m. burst := make([]Point, 0, 16) @@ -112,28 +112,78 @@ func TestProjectWaitsForEnoughHistory(t *testing.T) { at := from.Add(time.Duration(i) * 102 * time.Minute / 15) burst = append(burst, Point{At: at, Used: 16_075_923 + int64(i)*(28_011_667-16_075_923)/15}) } - f := Project(burst, now) + f := Project(burst, now, time.Time{}) assert.Nil(t, f.Rate7d, "an hour and a half is no weekly rate") assert.Nil(t, f.Rate30d) assert.Empty(t, f.RateUsed) assert.InDelta(t, 1.7, f.HistoryHours, 0.01) assert.Equal(t, 24.0, f.Rate7dMinHistoryHours) - assert.Equal(t, 168.0, f.Rate30dMinHistoryHours) + assert.Equal(t, 336.0, f.Rate30dMinHistoryHours) three := linear(3, time.Hour, 0, 1<<30, 1<<40) - f = Project(three, now) + f = Project(three, now, time.Time{}) require.NotNil(t, f.Rate7d, "three days is enough for the weekly rate") assert.Nil(t, f.Rate30d, "and not for the monthly one") assert.Equal(t, "7d", f.RateUsed) assert.InDelta(t, 72.0, f.HistoryHours, 0.01) + + // Ten days fill the weekly window and are still no monthly rate: the two + // would be fitted over nearly the same days. + ten := linear(10, time.Hour, 0, 1<<30, 1<<40) + f = Project(ten, now, time.Time{}) + require.NotNil(t, f.Rate7d) + assert.Nil(t, f.Rate30d, "ten days is no monthly rate") + f = Project(linear(15, time.Hour, 0, 1<<30, 1<<40), now, time.Time{}) + assert.NotNil(t, f.Rate30d, "fifteen days is") +} + +// firstBoot is #2203's store: 16 MB to 28 MB over its first half hour of +// setup, then flat, sampled every fifteen minutes for span. +func firstBoot(span time.Duration) []Point { + from := now.Add(-span) + var out []Point + for at := from; !at.After(now); at = at.Add(15 * time.Minute) { + used := int64(28_000_000) + if age := at.Sub(from); age < 30*time.Minute { + used = 16_000_000 + int64(12_000_000*age.Minutes()/30) + } + out = append(out, Point{At: at, Used: used, Total: new(int64(1 << 30))}) + } + return out +} + +// TestProjectLeavesTheFirstDayOut is #2203: a new install's setup is no +// growth. Fitted from its first sample, a store that climbed for half an hour +// and then held its size reads as growing; with its first day left out it +// reads as flat, gives no fill date, and says it needs a day more history. +func TestProjectLeavesTheFirstDayOut(t *testing.T) { + young := firstBoot(150 * time.Minute) + born := young[0].At + f := Project(young, now, born) + assert.Nil(t, f.Rate7d, "two and a half hours is no rate") + assert.Nil(t, f.ExhaustionAt) + assert.Equal(t, 48.0, f.Rate7dMinHistoryHours, "the first day and then a day") + assert.Equal(t, 360.0, f.Rate30dMinHistoryHours, "the first day and then two weeks") + + days := firstBoot(3 * day) + fitted := Project(days, now, time.Time{}) + require.NotNil(t, fitted.Rate7d) + assert.Positive(t, *fitted.Rate7d, "fitted from the first sample, setup reads as growth") + require.NotNil(t, fitted.ExhaustionAt) + + f = Project(days, now, days[0].At) + require.NotNil(t, f.Rate7d) + assert.Zero(t, *f.Rate7d, "after the first day the store holds its size") + assert.Nil(t, f.ExhaustionAt, "and has no fill date") + assert.Empty(t, f.RateUsed) } // TestProjectFlatStoreIsZero is #2201's second finding: a store holding one // size at every sample grows at exactly zero, not at the rounding error of // sums near 1e18. func TestProjectFlatStoreIsZero(t *testing.T) { - flat := linear(10, 7*time.Minute, 16_801_792, 0, 1<<40) - f := Project(flat, now) + flat := linear(15, 7*time.Minute, 16_801_792, 0, 1<<40) + f := Project(flat, now, time.Time{}) require.NotNil(t, f.Rate7d) require.NotNil(t, f.Rate30d) assert.Zero(t, *f.Rate7d) @@ -142,7 +192,7 @@ func TestProjectFlatStoreIsZero(t *testing.T) { // A big store gaining a little still reads its growth. creep := linear(10, 7*time.Minute, 1<<40, 4096, 1<<41) - f = Project(creep, now) + f = Project(creep, now, time.Time{}) require.NotNil(t, f.Rate7d) assert.InDelta(t, 4096, *f.Rate7d, 64) } @@ -166,7 +216,7 @@ func TestSlower(t *testing.T) { // its days left and no date, rather than one overflowed into the past. func TestProjectFarOffHasNoDate(t *testing.T) { points := linear(30, time.Hour, 0, 1<<20, 1<<50) - f := Project(points, now) + f := Project(points, now, time.Time{}) require.NotNil(t, f.DaysLeft) assert.Greater(t, *f.DaysLeft, 106752.0) assert.Nil(t, f.ExhaustionAt) diff --git a/internal/platform/storagecap/service.go b/internal/platform/storagecap/service.go index 7a4bb60b3..4ee7ab7fa 100644 --- a/internal/platform/storagecap/service.go +++ b/internal/platform/storagecap/service.go @@ -128,8 +128,16 @@ func (s *Service) Stop() { } // Pass is one iteration: read every store, record a sample of each, drop the -// history past the settings' period, and evaluate the alerts. +// history past the settings' period, and evaluate the alerts. A pass within +// most of the interval of the last sample is skipped: another replica took it. func (s *Service) Pass(ctx context.Context) error { + recent, err := s.sampledRecently(ctx) + if err != nil { + return err + } + if recent { + return bgloop.ErrSkipped + } settings, err := Read(ctx, s.d.Settings) if err != nil { return err @@ -152,6 +160,24 @@ func (s *Service) Pass(ctx context.Context) error { return nil } +// recentFraction is the share of the interval a sample counts as recent for: +// nine tenths, so a timer that fires a little early does not skip its turn. +const recentFraction = 0.9 + +// sampledRecently reports whether a sample was taken within most of the +// interval (#2203). Every replica runs the loop on its own timer, and the lock +// is held only for a pass, so a replica whose turn came just after another's +// pass would otherwise sample the same tick again. +func (s *Service) sampledRecently(ctx context.Context) (bool, error) { + since := s.d.Now().UTC().Add(-time.Duration(float64(s.d.Interval) * recentFraction)) + var recent bool + if err := s.d.DB.QueryRowContext(ctx, + `SELECT EXISTS (SELECT 1 FROM storage_samples WHERE sampled_at > $1)`, since).Scan(&recent); err != nil { + return false, fmt.Errorf(errReadingHistory, err) + } + return recent, nil +} + // spoolGone is how long a replica's spool goes unreported before its volume // is taken to be gone rather than unread: a replica replaced in a rollout // does not keep its alerts open. @@ -366,6 +392,10 @@ func (s *Service) project(ctx context.Context, r *Report) error { if err != nil { return err } + born, err := s.births(ctx, r.GeneratedAt.Add(-time.Duration(r.HistoryDays)*day+day)) + if err != nil { + return err + } for i := range r.Stores { st := &r.Stores[i] if st.TotalBytes != nil { @@ -374,11 +404,38 @@ func (s *Service) project(ctx context.Context, r *Report) error { st.FreeBytes, st.PercentUsed = &free, &pct } points := slices.Concat(history[st.Store], []Point{{At: r.GeneratedAt, Used: st.UsedBytes, Total: st.TotalBytes}}) - st.Forecast = Project(points, r.GeneratedAt) + st.Forecast = Project(points, r.GeneratedAt, born[st.Store]) } return nil } +// births is when each store's history began, for the stores whose first +// sample is after kept: a store whose first sample is older may have had its +// first days pruned, and its earliest sample kept is not its first. +func (s *Service) births(ctx context.Context, kept time.Time) (map[string]time.Time, error) { + rows, err := s.d.DB.QueryContext(ctx, + `SELECT store, min(sampled_at) FROM storage_samples GROUP BY store HAVING min(sampled_at) > $1`, kept) + if err != nil { + return nil, fmt.Errorf(errReadingHistory, err) + } + defer func() { _ = rows.Close() }() + out := map[string]time.Time{} + for rows.Next() { + var ( + store string + first time.Time + ) + if err := rows.Scan(&store, &first); err != nil { + return nil, fmt.Errorf("scanning storage history: %w", err) + } + out[store] = first.UTC() + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf(errReadingHistory, err) + } + return out, nil +} + // historySince is every store's samples since since, oldest first. func (s *Service) historySince(ctx context.Context, since time.Time) (map[string][]Point, error) { rows, err := s.d.DB.QueryContext(ctx, diff --git a/internal/platform/storagecap/service_realdb_integration_test.go b/internal/platform/storagecap/service_realdb_integration_test.go index 29da54ef0..beb934afa 100644 --- a/internal/platform/storagecap/service_realdb_integration_test.go +++ b/internal/platform/storagecap/service_realdb_integration_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/txn2/mcp-data-platform/internal/bgloop" "github.com/txn2/mcp-data-platform/internal/platform/levelalert" "github.com/txn2/mcp-data-platform/internal/testdb" "github.com/txn2/mcp-data-platform/internal/webhook/whstore" @@ -64,3 +65,44 @@ func TestPassRealDB(t *testing.T) { require.NoError(t, err) assert.Equal(t, map[string]int64{"portal": 1000}, budgetsRead) } + +// TestPassOncePerTickRealDB is #2203's fourth item: two replicas whose +// timers fire in the same tick take one sample between them, the second +// finding the first's; a tick an interval later samples again. The store's +// first sample is its birth, and its first day is left out of the fit. +func TestPassOncePerTickRealDB(t *testing.T) { + db := testdb.New(t) + ctx := context.Background() + settings := NewSettingsStore(db) + at := time.Date(2026, 10, 20, 3, 24, 7, 0, time.UTC) + replica := func() *Service { + return New(Deps{ + DB: db, Settings: settings, Engine: levelalert.New(levelalert.NewPostgresStore(db), nil), + Interval: 15 * time.Minute, Now: func() time.Time { return at }, + }) + } + a, b := replica(), replica() + samples := func() int { + var n int + require.NoError(t, db.QueryRowContext(ctx, `SELECT count(*) FROM storage_samples WHERE store = 'database'`).Scan(&n)) + return n + } + + require.NoError(t, a.Pass(ctx)) + at = at.Add(400 * time.Millisecond) + require.ErrorIs(t, b.Pass(ctx), bgloop.ErrSkipped, "the second replica in one tick") + assert.Equal(t, 1, samples()) + + at = at.Add(15 * time.Minute) + require.NoError(t, b.Pass(ctx)) + assert.Equal(t, 2, samples(), "the next tick samples again") + + r, err := b.Report(ctx) + require.NoError(t, err) + for _, s := range r.Stores { + if s.Store == "database" { + assert.Nil(t, s.Forecast.Rate7d) + assert.Equal(t, 48.0, s.Forecast.Rate7dMinHistoryHours, "a store born a quarter hour ago waits out its first day") + } + } +} diff --git a/internal/platform/storagecap/service_test.go b/internal/platform/storagecap/service_test.go index e32cb1fe9..4982a4b4c 100644 --- a/internal/platform/storagecap/service_test.go +++ b/internal/platform/storagecap/service_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/txn2/mcp-data-platform/internal/bgloop" "github.com/txn2/mcp-data-platform/internal/platform/levelalert" "github.com/txn2/mcp-data-platform/internal/platform/settingsjson" "github.com/txn2/mcp-data-platform/internal/webhook/whstore" @@ -66,6 +67,18 @@ func expectReadings(mock sqlmock.Sqlmock, dbBytes int64) { WillReturnRows(sqlmock.NewRows([]string{"store", "at", "used", "total"}). AddRow("database", now.Add(-10*day), int64(500), int64(1000)). AddRow("database", now.Add(-5*day), int64(700), nil)) + mock.ExpectQuery(`SELECT store, min\(sampled_at\) FROM storage_samples GROUP BY store`). + WithArgs(now.Add(-DefaultHistoryDays*day + day)). + WillReturnRows(sqlmock.NewRows([]string{"store", "first"}).AddRow("database", now.Add(-10*day))) +} + +// recentQ is the check a pass makes for a sample another replica took. +const recentQ = `SELECT EXISTS \(SELECT 1 FROM storage_samples WHERE sampled_at > \$1\)` + +// expectNotSampled queues the check finding no recent sample. +func expectNotSampled(mock sqlmock.Sqlmock) { + mock.ExpectQuery(recentQ).WithArgs(now.Add(-DefaultInterval * 9 / 10)). + WillReturnRows(sqlmock.NewRows([]string{"recent"}).AddRow(false)) } // svcRig is a Service over sqlmock with the sender and alert store it routes @@ -109,6 +122,7 @@ func TestPassSamplesAndAlerts(t *testing.T) { } rig := newSvc(t, settings, spools) svc, mock, sender, alerts := rig.svc, rig.mock, rig.sender, rig.alerts + expectNotSampled(mock) expectReadings(mock, 950) for range 5 { mock.ExpectExec(`INSERT INTO storage_samples`).WillReturnResult(sqlmock.NewResult(0, 1)) @@ -127,6 +141,7 @@ func TestPassSamplesAndAlerts(t *testing.T) { // The next pass finds the database back under its thresholds: resolved. sender.keys = nil settings.stored.Value.DatabaseLimitBytes = 100000 + expectNotSampled(mock) expectReadings(mock, 950) for range 5 { mock.ExpectExec(`INSERT INTO storage_samples`).WillReturnResult(sqlmock.NewResult(0, 1)) @@ -192,7 +207,7 @@ func TestReportClusterFailureIsShownNotFatal(t *testing.T) { func TestReportFailures(t *testing.T) { ctx := context.Background() boom := errors.New("down") - steps := []string{"size", "tables", "usage", "reconcile", "scan", "spools", "history"} + steps := []string{"size", "tables", "usage", "reconcile", "scan", "spools", "history", "births"} for i, step := range steps { t.Run(step, func(t *testing.T) { spools := func(context.Context) ([]whstore.SpoolState, error) { @@ -205,6 +220,7 @@ func TestReportFailures(t *testing.T) { svc, mock := rig.svc, rig.mock queries := []string{ `pg_database_size`, `FROM pg_class`, `FROM storage_usage`, `FROM storage_reconciles`, `FROM storage_scans`, "", `FROM storage_samples`, + `min\(sampled_at\)`, } for j := range i { if queries[j] == "" { @@ -239,6 +255,8 @@ func expectStep(mock sqlmock.Sqlmock, j int) { mock.ExpectQuery(`FROM storage_reconciles`).WillReturnRows(sqlmock.NewRows([]string{"a", "b", "c", "d"})) case 4: mock.ExpectQuery(`FROM storage_scans`).WillReturnRows(sqlmock.NewRows([]string{"a", "b", "c"})) + case 6: + mock.ExpectQuery(`FROM storage_samples`).WillReturnRows(sqlmock.NewRows([]string{"a", "b", "c", "d"})) } } @@ -246,12 +264,19 @@ func TestPassFailures(t *testing.T) { ctx := context.Background() boom := errors.New("down") t.Run("settings", func(t *testing.T) { - svc := newSvc(t, &fakeSettings{err: boom}, nil).svc - require.Error(t, svc.Pass(ctx)) + rig := newSvc(t, &fakeSettings{err: boom}, nil) + expectNotSampled(rig.mock) + require.Error(t, rig.svc.Pass(ctx)) + }) + t.Run("recent", func(t *testing.T) { + rig := newSvc(t, &fakeSettings{}, nil) + rig.mock.ExpectQuery(recentQ).WillReturnError(boom) + require.ErrorContains(t, rig.svc.Pass(ctx), "reading storage history") }) t.Run("record", func(t *testing.T) { rig := newSvc(t, &fakeSettings{}, nil) svc, mock := rig.svc, rig.mock + expectNotSampled(mock) expectReadings(mock, 1) mock.ExpectExec(`INSERT INTO storage_samples`).WillReturnError(boom) require.ErrorContains(t, svc.Pass(ctx), "recording a storage sample") @@ -259,6 +284,7 @@ func TestPassFailures(t *testing.T) { t.Run("prune", func(t *testing.T) { rig := newSvc(t, &fakeSettings{}, nil) svc, mock := rig.svc, rig.mock + expectNotSampled(mock) expectReadings(mock, 1) for range 3 { mock.ExpectExec(`INSERT INTO storage_samples`).WillReturnResult(sqlmock.NewResult(0, 1)) @@ -269,11 +295,41 @@ func TestPassFailures(t *testing.T) { t.Run("report", func(t *testing.T) { rig := newSvc(t, &fakeSettings{}, nil) svc, mock := rig.svc, rig.mock + expectNotSampled(mock) mock.ExpectQuery(`pg_database_size`).WillReturnError(boom) require.Error(t, svc.Pass(ctx)) }) } +// TestPassSkipsATickAnotherReplicaSampled is #2203: the lock is held only for +// a pass, so a replica whose turn comes just after another's finds that +// replica's sample and takes none of its own, and evaluates no alert. +func TestPassSkipsATickAnotherReplicaSampled(t *testing.T) { + rig := newSvc(t, &fakeSettings{}, nil) + rig.mock.ExpectQuery(recentQ).WithArgs(now.Add(-DefaultInterval * 9 / 10)). + WillReturnRows(sqlmock.NewRows([]string{"recent"}).AddRow(true)) + require.ErrorIs(t, rig.svc.Pass(context.Background()), bgloop.ErrSkipped) + require.NoError(t, rig.mock.ExpectationsWereMet()) + assert.Empty(t, rig.sender.keys) +} + +// TestBirthsFailures: a store's first sample is its birth only +// when nothing before it could have been pruned; a failed read is an error. +func TestBirthsFailures(t *testing.T) { + boom := errors.New("down") + rig := newSvc(t, &fakeSettings{}, nil) + rig.mock.ExpectQuery(`min\(sampled_at\)`).WillReturnError(boom) + _, err := rig.svc.births(context.Background(), now) + require.Error(t, err) + rig.mock.ExpectQuery(`min\(sampled_at\)`).WillReturnRows(sqlmock.NewRows([]string{"store"}).AddRow("database")) + _, err = rig.svc.births(context.Background(), now) + require.Error(t, err) + rig.mock.ExpectQuery(`min\(sampled_at\)`).WillReturnRows( + sqlmock.NewRows([]string{"store", "first"}).AddRow("database", now).RowError(0, boom)) + _, err = rig.svc.births(context.Background(), now) + require.Error(t, err) +} + func TestHistory(t *testing.T) { ctx := context.Background() rig := newSvc(t, &fakeSettings{}, nil) diff --git a/internal/portal/assetrefs/declare.go b/internal/portal/assetrefs/declare.go index 77fed93bc..a99ad934c 100644 --- a/internal/portal/assetrefs/declare.go +++ b/internal/portal/assetrefs/declare.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "log/slog" + "slices" "strings" "github.com/txn2/mcp-data-platform/internal/logsan" @@ -268,6 +269,73 @@ func (d *Declarer) Apply( return refs, nil } +// Widen records every declared reference the asset does not have yet beside +// the ones it has, ahead of a write whose new content uses them (#2234). The +// new version is what makes the asset owed a tile, and the tile worker may draw +// it the moment it exists, so its files must already be granted then; the +// references the write drops are dropped by the Apply after it, since the +// content still current until then uses them. Each added reference gets the +// token Apply keeps. +// +// restore puts the references back as they were, for a write that failed; it +// does nothing when Widen added nothing. +func (d *Declarer) Widen( + ctx context.Context, assetID string, declared []Declared, author string, +) (restore func(context.Context) error, err error) { + if !d.Available() { + return nil, errNoRefStore() + } + existing, err := d.refs.ListByAsset(ctx, assetID) + if err != nil { + return nil, fmt.Errorf("reading existing references: %w", err) + } + added, err := missingRefs(assetID, existing, declared, author) + if err != nil { + return nil, err + } + if len(added) == 0 { + return func(context.Context) error { return nil }, nil + } + if err := d.refs.Replace(ctx, assetID, slices.Concat(existing, added)); err != nil { + return nil, fmt.Errorf("recording references: %w", err) + } + for _, ref := range added { + LogGranted(assetID, ref) + } + return func(ctx context.Context) error { + if err := d.refs.Replace(ctx, assetID, existing); err != nil { + return fmt.Errorf("restoring references: %w", err) + } + return nil + }, nil +} + +// missingRefs is the declared references existing does not hold, each with a +// new token, positioned after existing. +func missingRefs(assetID string, existing []Ref, declared []Declared, author string) ([]Ref, error) { + have := make(map[string]bool, len(existing)) + for _, ref := range existing { + have[refKey(ref.TargetKind, ref.TargetID)] = true + } + var added []Ref + for _, dec := range declared { + key := refKey(dec.Kind, dec.TargetID) + if have[key] { + continue + } + have[key] = true + token, err := tokenFor(nil, key) + if err != nil { + return nil, err + } + added = append(added, Ref{ + AssetID: assetID, TargetKind: dec.Kind, TargetID: dec.TargetID, URI: dec.URI, + RefToken: token, Position: len(existing) + len(added), DeclaredBy: author, + }) + } + return added, nil +} + // DeclaredURIs returns the reference strings an asset declares now, in declared // order: what a write that leaves the references alone is judged against when // it reports the references its content names undeclared (#1875). A declarer diff --git a/internal/portal/assetrefs/declare_test.go b/internal/portal/assetrefs/declare_test.go index 2d77ee390..b6550a511 100644 --- a/internal/portal/assetrefs/declare_test.go +++ b/internal/portal/assetrefs/declare_test.go @@ -816,3 +816,64 @@ func TestConfig(t *testing.T) { require.Error(t, bad.Validate()) assert.Equal(t, assetrefs.DefaultMaxRefs, bad.Resolved()) } + +// TestWidenAddsWithoutDropping is #2234: ahead of a content write, the +// references it declares are recorded beside the ones the asset has, keeping +// their tokens; restore puts the list back; a declaration that adds nothing +// writes nothing; the token Widen minted is the one Apply keeps. +func TestWidenAddsWithoutDropping(t *testing.T) { + store := newFakeRefs() + d := declarer(store) + logo := assetrefs.Declared{Kind: assetrefs.TargetResource, TargetID: "res-logo", URI: logoURI} + other := assetrefs.Declared{Kind: assetrefs.TargetResource, TargetID: "res-other", URI: "mcp://global/brand/other.png"} + first, err := d.Apply(t.Context(), testAssetID, []assetrefs.Declared{logo}, author) + require.NoError(t, err) + + restore, err := d.Widen(t.Context(), testAssetID, []assetrefs.Declared{other, other}, author) + require.NoError(t, err) + require.NotNil(t, restore) + widened := store.byAsset[testAssetID] + require.Len(t, widened, 2, "the kept reference and the added one, once") + assert.Equal(t, first[0].RefToken, widened[0].RefToken) + assert.Equal(t, "res-other", widened[1].TargetID) + assert.Equal(t, 1, widened[1].Position) + + applied, err := d.Apply(t.Context(), testAssetID, []assetrefs.Declared{other}, author) + require.NoError(t, err) + assert.Equal(t, widened[1].RefToken, applied[0].RefToken, "Apply keeps the token Widen minted") + + require.NoError(t, restore(t.Context())) + require.Len(t, store.byAsset[testAssetID], 1) + assert.Equal(t, "res-logo", store.byAsset[testAssetID][0].TargetID) + + none, err := d.Widen(t.Context(), testAssetID, []assetrefs.Declared{logo}, author) + require.NoError(t, err) + assert.Len(t, store.byAsset[testAssetID], 1, "a declaration the asset already holds adds nothing") + require.NoError(t, none(t.Context())) + assert.Len(t, store.byAsset[testAssetID], 1, "and restoring it changes nothing") +} + +// TestWidenReportsStoreFailures: every store failure is reported, restore's +// included, and an unavailable declarer refuses. +func TestWidenReportsStoreFailures(t *testing.T) { + declared := []assetrefs.Declared{{Kind: assetrefs.TargetResource, TargetID: "res-logo", URI: logoURI}} + + _, err := (*assetrefs.Declarer)(nil).Widen(t.Context(), testAssetID, declared, author) + require.Error(t, err) + + listFails := newFakeRefs() + listFails.listErr = errStore + _, err = declarer(listFails).Widen(t.Context(), testAssetID, declared, author) + require.ErrorIs(t, err, errStore) + + writeFails := newFakeRefs() + writeFails.putErr = errStore + _, err = declarer(writeFails).Widen(t.Context(), testAssetID, declared, author) + require.ErrorIs(t, err, errStore) + + restoreFails := newFakeRefs() + restore, err := declarer(restoreFails).Widen(t.Context(), testAssetID, declared, author) + require.NoError(t, err) + restoreFails.putErr = errStore + require.ErrorIs(t, restore(t.Context()), errStore) +} diff --git a/internal/thumbdue/thumbdue.go b/internal/thumbdue/thumbdue.go index 25acedfdf..a25155601 100644 --- a/internal/thumbdue/thumbdue.go +++ b/internal/thumbdue/thumbdue.go @@ -20,10 +20,8 @@ import ( "encoding/hex" "fmt" "io" - "log/slog" - "time" - "github.com/txn2/mcp-data-platform/internal/logsan" + "github.com/txn2/mcp-data-platform/internal/advisorylock" ) // NotifyChannel is the channel the trigger notifies when a row becomes due. @@ -44,9 +42,6 @@ const ( // holds row locks on more than this many rows at a time. const chunk = 2000 -// unlockTimeout bounds the advisory unlock after a sweep. -const unlockTimeout = 5 * time.Second - // The advisory locks the sweeps run under, one per table, so two replicas // starting together sweep a table once. const ( @@ -97,44 +92,33 @@ func Sweep(ctx context.Context, db *sql.DB, table Table, rule string) (int64, er if err != nil { return 0, err } - conn, err := db.Conn(ctx) + release, got, err := advisorylock.Try(ctx, db, advisorylock.ID(key)) if err != nil { - return 0, fmt.Errorf("thumbdue: acquiring a connection for the sweep: %w", err) - } - defer func() { _ = conn.Close() }() - var got bool - if err := conn.QueryRowContext(ctx, "SELECT pg_try_advisory_lock($1)", key).Scan(&got); err != nil { return 0, fmt.Errorf("thumbdue: taking the sweep lock: %w", err) } if !got { return 0, nil } - defer func() { - unlockCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), unlockTimeout) - defer cancel() - if _, uerr := conn.ExecContext(unlockCtx, "SELECT pg_advisory_unlock($1)", key); uerr != nil { - slog.WarnContext(ctx, "thumbnails: sweep unlock failed", "table", string(table), "error", logsan.SanitizeForLog(uerr.Error())) - } - }() - return sweepLocked(ctx, conn, table, rule) + defer release() + return sweepLocked(ctx, db, table, rule) } // sweepLocked is Sweep once its lock is held: mark the table unless it was // swept under rule, then record rule. -func sweepLocked(ctx context.Context, conn *sql.Conn, table Table, rule string) (int64, error) { +func sweepLocked(ctx context.Context, db *sql.DB, table Table, rule string) (int64, error) { var recorded string - err := conn.QueryRowContext(ctx, `SELECT rule FROM thumbnail_sweeps WHERE subject = $1`, string(table)).Scan(&recorded) + err := db.QueryRowContext(ctx, `SELECT rule FROM thumbnail_sweeps WHERE subject = $1`, string(table)).Scan(&recorded) if err != nil && err != sql.ErrNoRows { //nolint:errorlint // database/sql returns ErrNoRows unwrapped return 0, fmt.Errorf("thumbdue: reading the sweep record: %w", err) } if recorded == rule { return 0, nil } - marked, err := markAll(ctx, conn, table) + marked, err := markAll(ctx, db, table) if err != nil { return marked, err } - if _, err := conn.ExecContext(ctx, ` + if _, err := db.ExecContext(ctx, ` INSERT INTO thumbnail_sweeps (subject, rule, swept_at) VALUES ($1, $2, now()) ON CONFLICT (subject) DO UPDATE SET rule = EXCLUDED.rule, swept_at = EXCLUDED.swept_at`, string(table), rule); err != nil { @@ -144,7 +128,7 @@ func sweepLocked(ctx context.Context, conn *sql.Conn, table Table, rule string) } // markAll marks table due chunk rows at a time, walking its primary key. -func markAll(ctx context.Context, conn *sql.Conn, table Table) (int64, error) { +func markAll(ctx context.Context, db *sql.DB, table Table) (int64, error) { query := markQuery(table) var marked int64 after := "" @@ -152,7 +136,7 @@ func markAll(ctx context.Context, conn *sql.Conn, table Table) (int64, error) { var n int64 var last sql.NullString // #nosec G701 -- table is one of the Table constants; every value is bound - if err := conn.QueryRowContext(ctx, query, after, chunk).Scan(&n, &last); err != nil { + if err := db.QueryRowContext(ctx, query, after, chunk).Scan(&n, &last); err != nil { return marked, fmt.Errorf("thumbdue: marking %s due: %w", string(table), err) } marked += n diff --git a/internal/upstreamauth/googlekey/googlekey.go b/internal/upstreamauth/googlekey/googlekey.go index 7a08e8220..a1c321fa0 100644 --- a/internal/upstreamauth/googlekey/googlekey.go +++ b/internal/upstreamauth/googlekey/googlekey.go @@ -153,7 +153,13 @@ type apiError struct { // APIHint is the operator's next step for a Google API refusing a call a // service-account connection made, or "" when the response is not one. A valid // token is not access: the API must be enabled in the account's Cloud project, -// and the account granted inside the product. body is the decoded response. +// the token must carry the API's scope, and the account must be granted inside +// the product. body is the decoded response. +// +// Every Google API refuses in one shape (error.code, error.status, +// error.details[].reason), and the token was issued by Google a moment before, +// so a 401 or 403 in that shape is read by its status and reasons alone, never +// by one product's message text (#2237). func APIHint(status int, body any) string { if status != http.StatusUnauthorized && status != http.StatusForbidden { return "" @@ -163,19 +169,19 @@ func APIHint(status int, body any) string { return "" } var e apiError - if json.Unmarshal(raw, &e) != nil { + if json.Unmarshal(raw, &e) != nil || e.Error.Status == "" { return "" } reasons := make([]string, 0, len(e.Error.Details)) for _, d := range e.Error.Details { reasons = append(reasons, d.Reason) } - msg := strings.ToLower(e.Error.Message) switch { case slices.Contains(reasons, "SERVICE_DISABLED"): return "the API is not enabled in the service account's Google Cloud project; enable it there (the error names the project and the API)" - case e.Error.Status == "PERMISSION_DENIED" || strings.Contains(msg, "cannot get profile"): + case slices.Contains(reasons, "ACCESS_TOKEN_SCOPE_INSUFFICIENT"): + return "the token does not carry the scope this API needs; add it to the connection's oauth_scope" + default: return "the token is valid but the service account has no access in this product; grant the service account's email access inside the product" } - return "" } diff --git a/internal/upstreamauth/googlekey/googlekey_test.go b/internal/upstreamauth/googlekey/googlekey_test.go index 265e6719a..df8e42ff6 100644 --- a/internal/upstreamauth/googlekey/googlekey_test.go +++ b/internal/upstreamauth/googlekey/googlekey_test.go @@ -118,19 +118,23 @@ func TestAPIHint(t *testing.T) { } disabled := decode(`{"error":{"code":403,"message":"Google Sheets API has not been used in project 1234567890 before or it is disabled.","status":"PERMISSION_DENIED","details":[{"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"SERVICE_DISABLED"}]}}`) denied := decode(`{"error":{"code":403,"message":"The caller does not have permission","status":"PERMISSION_DENIED"}}`) - profile := decode(`{"error":{"code":401,"message":"Cannot get profile for this user.","status":"UNAUTHENTICATED"}}`) + unauthenticated := decode(`{"error":{"code":401,"message":"Request had invalid authentication credentials.","status":"UNAUTHENTICATED"}}`) + anyMessage := decode(`{"error":{"code":401,"message":"Something only this product says.","status":"UNAUTHENTICATED"}}`) + scope := decode(`{"error":{"code":403,"message":"Request had insufficient authentication scopes.","status":"PERMISSION_DENIED","details":[{"@type":"type.googleapis.com/google.rpc.ErrorInfo","reason":"ACCESS_TOKEN_SCOPE_INSUFFICIENT"}]}}`) for name, tc := range map[string]struct { status int body any want string }{ - "an API not enabled": {http.StatusForbidden, disabled, "not enabled in the service account's Google Cloud project"}, - "no access in product": {http.StatusForbidden, denied, "grant the service account's email access"}, - "no profile in the product": {http.StatusUnauthorized, profile, "grant the service account's email access"}, - "a success": {http.StatusOK, denied, ""}, - "not Google's shape": {http.StatusForbidden, decode(`{"message":"forbidden"}`), ""}, - "a body that is text": {http.StatusForbidden, "forbidden", ""}, - "an unmarshalable body": {http.StatusForbidden, func() {}, ""}, + "an API not enabled": {http.StatusForbidden, disabled, "not enabled in the service account's Google Cloud project"}, + "a scope the token lacks": {http.StatusForbidden, scope, "add it to the connection's oauth_scope"}, + "no access in product": {http.StatusForbidden, denied, "grant the service account's email access"}, + "a 401 in Google's shape": {http.StatusUnauthorized, unauthenticated, "grant the service account's email access"}, + "a 401 with any other message": {http.StatusUnauthorized, anyMessage, "grant the service account's email access"}, + "a success": {http.StatusOK, denied, ""}, + "not Google's shape": {http.StatusForbidden, decode(`{"message":"forbidden"}`), ""}, + "a body that is text": {http.StatusForbidden, "forbidden", ""}, + "an unmarshalable body": {http.StatusForbidden, func() {}, ""}, } { if got := APIHint(tc.status, tc.body); (tc.want == "" && got != "") || !strings.Contains(got, tc.want) { t.Errorf("%s: hint = %q, want %q", name, got, tc.want) diff --git a/pkg/audit/postgres/store.go b/pkg/audit/postgres/store.go index 84d6a87ba..d6d730e79 100644 --- a/pkg/audit/postgres/store.go +++ b/pkg/audit/postgres/store.go @@ -14,7 +14,9 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/lib/pq" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" + "github.com/txn2/mcp-data-platform/internal/logsan" "github.com/txn2/mcp-data-platform/pkg/audit" ) @@ -554,54 +556,26 @@ func (s *Store) runMaintenanceTick(ctx context.Context) error { }) } -// unlockTimeout caps the time the deferred advisory_unlock call may take. -// The unlock runs on a detached context so it still fires when the parent -// context has been canceled by Close, but it must not block shutdown -// indefinitely if the database itself is unreachable. -const unlockTimeout = 5 * time.Second - // runUnderMaintenanceLock attempts to acquire the audit maintenance advisory // lock and, if successful, invokes fn. If another replica already holds the // lock, fn is not invoked and bgloop.ErrSkipped is returned; when the // database is unreachable, the error. The next tick will retry. // -// The lock is taken on a dedicated connection so the acquire and release -// happen on the same PostgreSQL session (advisory locks are session-scoped). -// fn itself uses s.db, which may draw other connections from the pool; those -// queries are not blocked by the lock. The lock only prevents OTHER replicas -// from running maintenance concurrently. -// -// The unlock uses a detached context with a short timeout so a canceled -// parent context (e.g. Close called during fn) cannot leave the advisory -// lock held on the pooled connection. +// The lock is taken on the process's lock session (internal/advisorylock), +// which every background lock shares, so holding it pins no connection of its +// own (#2169). fn uses s.db; the lock only prevents OTHER replicas from +// running maintenance concurrently. func (s *Store) runUnderMaintenanceLock(ctx context.Context, fn func(context.Context) error) error { - conn, err := s.db.Conn(ctx) + release, got, err := advisorylock.Try(ctx, s.db, advisorylock.ID(auditMaintenanceLockKey)) if err != nil { - slog.WarnContext(ctx, "audit cleanup: acquire connection for lock", slogKeyError, err) - return fmt.Errorf("audit cleanup: acquire connection for lock: %w", err) - } - defer func() { _ = conn.Close() }() - - var got bool - if err := conn.QueryRowContext(ctx, - "SELECT pg_try_advisory_lock($1)", auditMaintenanceLockKey, - ).Scan(&got); err != nil { - slog.WarnContext(ctx, "audit cleanup: try advisory lock", slogKeyError, err) + slog.WarnContext(ctx, "audit cleanup: try advisory lock", slogKeyError, logsan.SanitizeForLog(err.Error())) return fmt.Errorf("audit cleanup: try advisory lock: %w", err) } if !got { // Another replica holds the lock; skip this tick. return bgloop.ErrSkipped } - defer func() { - unlockCtx, cancel := context.WithTimeout(context.Background(), unlockTimeout) - defer cancel() - if _, err := conn.ExecContext(unlockCtx, - "SELECT pg_advisory_unlock($1)", auditMaintenanceLockKey, - ); err != nil { - slog.WarnContext(ctx, "audit cleanup: advisory unlock", slogKeyError, err) - } - }() + defer release() return fn(ctx) } diff --git a/pkg/connoauth/locker_test.go b/pkg/connoauth/locker_test.go new file mode 100644 index 000000000..3628e14a3 --- /dev/null +++ b/pkg/connoauth/locker_test.go @@ -0,0 +1,47 @@ +package connoauth + +import ( + "context" + "errors" + "regexp" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +// The refresher's lock is a try-lock on the process's lock session (#2169): +// taken, it is released by its release; held elsewhere, it is refused; a +// statement that fails is an error naming the lock. +func TestPostgresLocker_TryLock(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = db.Close() }) + locker := NewPostgresLocker(db) + key := Key{Kind: KindAPI, Name: "crm"} + lockQ := regexp.QuoteMeta("SELECT pg_try_advisory_lock($1)") + unlockQ := regexp.QuoteMeta("SELECT pg_advisory_unlock($1)") + + mock.ExpectQuery(lockQ).WithArgs(advisoryLockKey(key)).WillReturnRows(sqlmock.NewRows([]string{"l"}).AddRow(true)) + mock.ExpectExec(unlockQ).WithArgs(advisoryLockKey(key)).WillReturnResult(sqlmock.NewResult(0, 0)) + release, ok, err := locker.TryLock(context.Background(), key) + if err != nil || !ok { + t.Fatalf("a free lock: ok=%v err=%v", ok, err) + } + release() + + mock.ExpectQuery(lockQ).WillReturnRows(sqlmock.NewRows([]string{"l"}).AddRow(false)) + if _, ok, err := locker.TryLock(context.Background(), key); err != nil || ok { + t.Fatalf("a lock held elsewhere: ok=%v err=%v", ok, err) + } + + down := errors.New("down") + mock.ExpectQuery(lockQ).WillReturnError(down) + if _, _, err := locker.TryLock(context.Background(), key); !errors.Is(err, down) { + t.Fatalf("a failed statement: %v", err) + } + if err := mock.ExpectationsWereMet(); err != nil { + t.Error(err) + } +} diff --git a/pkg/connoauth/refresher.go b/pkg/connoauth/refresher.go index e796416cf..a9433f25a 100644 --- a/pkg/connoauth/refresher.go +++ b/pkg/connoauth/refresher.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/txn2/mcp-data-platform/internal/advisorylock" "github.com/txn2/mcp-data-platform/internal/bgloop" "github.com/txn2/mcp-data-platform/pkg/authevents" "github.com/txn2/mcp-data-platform/pkg/observability" @@ -95,10 +96,8 @@ func (NoopLocker) TryLock(_ context.Context, _ Key) (release func(), ok bool, er } // PostgresLocker wraps a *sql.DB with pg_try_advisory_lock semantics. -// The lock is held in the session associated with the *sql.Conn the -// locker checks out from the pool; release() closes the connection -// back to the pool which Postgres treats as a session end (and -// auto-releases the lock). +// The lock is held on the process's lock session, which every background +// try-lock shares. type PostgresLocker struct { db *sql.DB } @@ -111,7 +110,9 @@ func NewPostgresLocker(db *sql.DB) *PostgresLocker { } // TryLock acquires a session-scoped advisory lock keyed by -// hashtext('connoauth-refresh:/'). The hash uses FNV +// hashtext('connoauth-refresh:/'), on the process's lock session +// (internal/advisorylock), so a refresh in flight pins no connection of its +// own (#2169). The hash uses FNV // here (Postgres-equivalent stability is not required because every // lock key is held by the same process for at most one tick) and // converts to a bigint for pg_try_advisory_lock. @@ -119,35 +120,11 @@ func (l *PostgresLocker) TryLock(ctx context.Context, k Key) (release func(), ok if !k.IsValid() { return nil, false, errInvalidKey } - conn, err := l.db.Conn(ctx) + release, ok, err = advisorylock.Try(ctx, l.db, advisorylock.ID(advisoryLockKey(k))) if err != nil { - return nil, false, fmt.Errorf("connoauth: locker checkout: %w", err) - } - keyID := advisoryLockKey(k) - var acquired bool - if err := conn.QueryRowContext(ctx, - `SELECT pg_try_advisory_lock($1)`, keyID).Scan(&acquired); err != nil { - _ = conn.Close() return nil, false, fmt.Errorf("connoauth: try lock: %w", err) } - if !acquired { - _ = conn.Close() - return nil, false, nil - } - release = func() { - // Use a short detached context so the unlock doesn't depend - // on the caller's ctx (a refresh that overran its tick - // timeout would otherwise leak the lock for the duration of - // the session-end-on-conn-close). - unlockCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - if _, err := conn.ExecContext(unlockCtx, `SELECT pg_advisory_unlock($1)`, keyID); err != nil { - slog.WarnContext(ctx, "connoauth: advisory unlock failed (lock released on conn close)", - logKeyKind, k.Kind, logKeyName, k.Name, logKeyError, err) - } - _ = conn.Close() - } - return release, true, nil + return release, ok, nil } // advisoryLockKey hashes "connoauth-refresh:/" into the diff --git a/pkg/database/migrate/migrate_unit_test.go b/pkg/database/migrate/migrate_unit_test.go index 0c8832953..e55d8960f 100644 --- a/pkg/database/migrate/migrate_unit_test.go +++ b/pkg/database/migrate/migrate_unit_test.go @@ -15,7 +15,7 @@ import ( ) const ( - migrateTestFileCount = 414 + migrateTestFileCount = 418 migrateTestSuccess = "success" migrateTestFactoryError = "factory error" ) diff --git a/pkg/database/migrate/migrations/000208_call_records_supersession_index.down.sql b/pkg/database/migrate/migrations/000208_call_records_supersession_index.down.sql new file mode 100644 index 000000000..afc589d54 --- /dev/null +++ b/pkg/database/migrate/migrations/000208_call_records_supersession_index.down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS idx_call_records_supersession; diff --git a/pkg/database/migrate/migrations/000208_call_records_supersession_index.up.sql b/pkg/database/migrate/migrations/000208_call_records_supersession_index.up.sql new file mode 100644 index 000000000..c7664b933 --- /dev/null +++ b/pkg/database/migrate/migrations/000208_call_records_supersession_index.up.sql @@ -0,0 +1,7 @@ +-- #2231: the supersession check a call record's outcome is read from looks for +-- a later call in the same session on the same kind and connection. It was +-- answered by intersecting the session index with the (kind, connection) +-- index, a fifth of a millisecond per record, which every list and count +-- filtered by outcome paid once per record in the catalog. +CREATE INDEX IF NOT EXISTS idx_call_records_supersession + ON call_records(session_id, kind, connection, created_at); diff --git a/pkg/database/migrate/migrations/000209_fts_name_words.down.sql b/pkg/database/migrate/migrations/000209_fts_name_words.down.sql new file mode 100644 index 000000000..d46e94e8e --- /dev/null +++ b/pkg/database/migrate/migrations/000209_fts_name_words.down.sql @@ -0,0 +1,82 @@ +CREATE OR REPLACE FUNCTION resource_fts(display_name text, description text, path text, filename text, tags text[], content_text text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + coalesce(display_name, '') || ' ' || + coalesce(description, '') || ' ' || + coalesce(path, '') || ' ' || + coalesce(filename, '') || ' ' || + coalesce(array_to_string(tags, ' '), '') || ' ' || + coalesce(content_text, '')); +$$; + +CREATE OR REPLACE FUNCTION portal_asset_fts(name text, description text, tags jsonb) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + coalesce(name, '') || ' ' || + coalesce(description, '') || ' ' || + coalesce(tags::text, '')); +$$; + +CREATE OR REPLACE FUNCTION portal_collection_fts(name text, description text, sections_text text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + coalesce(name, '') || ' ' || + coalesce(description, '') || ' ' || + coalesce(sections_text, '')); +$$; + +CREATE OR REPLACE FUNCTION prompt_fts(display_name text, name text, description text, content text, tags text[]) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + coalesce(nullif(display_name, ''), name) || ' ' || + coalesce(description, '') || ' ' || + coalesce(content, '') || ' ' || + coalesce(array_to_string(tags, ' '), '')); +$$; + +CREATE OR REPLACE FUNCTION portal_knowledge_page_fts(title text, body text, tags jsonb) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + coalesce(title, '') || ' ' || + coalesce(body, '') || ' ' || + coalesce(tags::text, '')); +$$; + +CREATE OR REPLACE FUNCTION script_fts(display_name text, name text, description text, category text, tags text[], params jsonb, source text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT setweight(to_tsvector('english', + coalesce(nullif(display_name, ''), name) || ' ' || + coalesce(description, '') || ' ' || + coalesce(category, '') || ' ' || + coalesce(array_to_string(tags, ' '), '') || ' ' || + CASE WHEN jsonb_typeof(params) = 'array' THEN + coalesce(( + SELECT string_agg( + coalesce(p->>'name', '') || ' ' || coalesce(p->>'description', ''), ' ') + FROM jsonb_array_elements(params) AS p), '') + ELSE '' END), 'A') + || setweight(to_tsvector('english', coalesce(source, '')), 'D'); +$$; + +CREATE OR REPLACE FUNCTION catalog_dataset_fts(name text, description text, tags text[], domain text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + coalesce(name, '') || ' ' || + coalesce(description, '') || ' ' || + coalesce(array_to_string(tags, ' '), '') || ' ' || + coalesce(domain, '')); +$$; + +REINDEX INDEX idx_resources_search_fts; +REINDEX INDEX idx_portal_assets_search_fts; +REINDEX INDEX idx_portal_collections_search_fts; +REINDEX INDEX idx_prompts_search_fts; +REINDEX INDEX idx_portal_knowledge_pages_search_fts; +REINDEX INDEX idx_scripts_search_fts; +REINDEX INDEX idx_catalog_datasets_search_fts; + +DROP INDEX IF EXISTS idx_memory_records_content_fts; +CREATE INDEX idx_memory_records_content_fts + ON memory_records USING gin (to_tsvector('english', content)); + +DROP FUNCTION IF EXISTS fts_name_words(text); diff --git a/pkg/database/migrate/migrations/000209_fts_name_words.up.sql b/pkg/database/migrate/migrations/000209_fts_name_words.up.sql new file mode 100644 index 000000000..538bd507a --- /dev/null +++ b/pkg/database/migrate/migrations/000209_fts_name_words.up.sql @@ -0,0 +1,103 @@ +-- #2230: a name is matched by its words. PostgreSQL's parser reads +-- "acceptance-1627-1792487495133911000" as the word "acceptance" and the +-- signed numbers -1627 and -1792487495133911000, and "q3-2024-report.csv" as +-- one file-name token, so a search for "acceptance 1627 1792487495133911000" +-- or "q3 2024 report" matched neither. fts_name_words keeps the text as it is +-- and adds it again with its separators read as spaces, so a name matches by +-- the words it is made of and still by itself. It is applied to the fields +-- that name a thing (names, titles, paths, file names, tags, categories), and +-- to a memory's content, which is short and is where an agent records an +-- identifier. +-- +-- The search functions below spell the expression out rather than call +-- fts_name_words: PostgreSQL 17 runs an index's functions with search_path set +-- to pg_catalog, where an unqualified call to a function of this schema is not +-- found. fts_name_words itself calls only pg_catalog, so the memory index and +-- the folder search call it. +CREATE OR REPLACE FUNCTION fts_name_words(t text) RETURNS text + LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT coalesce(t, '') || ' ' || regexp_replace(coalesce(t, ''), '[-_./:]+', ' ', 'g'); +$$; + +CREATE OR REPLACE FUNCTION resource_fts(display_name text, description text, path text, filename text, tags text[], content_text text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + (coalesce(display_name, '') || ' ' || regexp_replace(coalesce(display_name, ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(description, '') || ' ' || + (coalesce(path, '') || ' ' || regexp_replace(coalesce(path, ''), '[-_./:]+', ' ', 'g')) || ' ' || + (coalesce(filename, '') || ' ' || regexp_replace(coalesce(filename, ''), '[-_./:]+', ' ', 'g')) || ' ' || + (coalesce(array_to_string(tags, ' '), '') || ' ' || regexp_replace(coalesce(array_to_string(tags, ' '), ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(content_text, '')); +$$; + +CREATE OR REPLACE FUNCTION portal_asset_fts(name text, description text, tags jsonb) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + (coalesce(name, '') || ' ' || regexp_replace(coalesce(name, ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(description, '') || ' ' || + (coalesce(tags::text, '') || ' ' || regexp_replace(coalesce(tags::text, ''), '[-_./:]+', ' ', 'g'))); +$$; + +CREATE OR REPLACE FUNCTION portal_collection_fts(name text, description text, sections_text text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + (coalesce(name, '') || ' ' || regexp_replace(coalesce(name, ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(description, '') || ' ' || + coalesce(sections_text, '')); +$$; + +CREATE OR REPLACE FUNCTION prompt_fts(display_name text, name text, description text, content text, tags text[]) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + (coalesce(coalesce(nullif(display_name, ''), name), '') || ' ' || regexp_replace(coalesce(coalesce(nullif(display_name, ''), name), ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(description, '') || ' ' || + coalesce(content, '') || ' ' || + (coalesce(array_to_string(tags, ' '), '') || ' ' || regexp_replace(coalesce(array_to_string(tags, ' '), ''), '[-_./:]+', ' ', 'g'))); +$$; + +CREATE OR REPLACE FUNCTION portal_knowledge_page_fts(title text, body text, tags jsonb) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + (coalesce(title, '') || ' ' || regexp_replace(coalesce(title, ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(body, '') || ' ' || + (coalesce(tags::text, '') || ' ' || regexp_replace(coalesce(tags::text, ''), '[-_./:]+', ' ', 'g'))); +$$; + +CREATE OR REPLACE FUNCTION script_fts(display_name text, name text, description text, category text, tags text[], params jsonb, source text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT setweight(to_tsvector('english', + (coalesce(coalesce(nullif(display_name, ''), name), '') || ' ' || regexp_replace(coalesce(coalesce(nullif(display_name, ''), name), ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(description, '') || ' ' || + (coalesce(category, '') || ' ' || regexp_replace(coalesce(category, ''), '[-_./:]+', ' ', 'g')) || ' ' || + (coalesce(array_to_string(tags, ' '), '') || ' ' || regexp_replace(coalesce(array_to_string(tags, ' '), ''), '[-_./:]+', ' ', 'g')) || ' ' || + CASE WHEN jsonb_typeof(params) = 'array' THEN + coalesce(( + SELECT string_agg( + coalesce(p->>'name', '') || ' ' || coalesce(p->>'description', ''), ' ') + FROM jsonb_array_elements(params) AS p), '') + ELSE '' END), 'A') + || setweight(to_tsvector('english', coalesce(source, '')), 'D'); +$$; + +CREATE OR REPLACE FUNCTION catalog_dataset_fts(name text, description text, tags text[], domain text) + RETURNS tsvector LANGUAGE sql IMMUTABLE PARALLEL SAFE AS $$ + SELECT to_tsvector('english', + (coalesce(name, '') || ' ' || regexp_replace(coalesce(name, ''), '[-_./:]+', ' ', 'g')) || ' ' || + coalesce(description, '') || ' ' || + (coalesce(array_to_string(tags, ' '), '') || ' ' || regexp_replace(coalesce(array_to_string(tags, ' '), ''), '[-_./:]+', ' ', 'g')) || ' ' || + (coalesce(domain, '') || ' ' || regexp_replace(coalesce(domain, ''), '[-_./:]+', ' ', 'g'))); +$$; + +-- An expression index holds what its function returned when each row was +-- written, so each index on a function changed above is built again. +REINDEX INDEX idx_resources_search_fts; +REINDEX INDEX idx_portal_assets_search_fts; +REINDEX INDEX idx_portal_collections_search_fts; +REINDEX INDEX idx_prompts_search_fts; +REINDEX INDEX idx_portal_knowledge_pages_search_fts; +REINDEX INDEX idx_scripts_search_fts; +REINDEX INDEX idx_catalog_datasets_search_fts; + +DROP INDEX IF EXISTS idx_memory_records_content_fts; +CREATE INDEX idx_memory_records_content_fts + ON memory_records USING gin (to_tsvector('english', fts_name_words(content))); diff --git a/pkg/memory/postgres.go b/pkg/memory/postgres.go index 1620ad19f..72be022a7 100644 --- a/pkg/memory/postgres.go +++ b/pkg/memory/postgres.go @@ -388,8 +388,9 @@ const rawRecordCols = "id, created_at, updated_at, created_by, persona, dimensio // ftsExpr is the Postgres full-text expression the lexical arm matches // and ranks against. It MUST be byte-identical to the expression the // idx_memory_records_content_fts GIN index is built on (migration -// 000054) or the planner will not use the index. -const ftsExpr = "to_tsvector('english', content)" +// 000209, which reads a memory's identifiers by their words, #2230) or the +// planner will not use the index. +const ftsExpr = "to_tsvector('english', fts_name_words(content))" // ftsRankNormalization is the ts_rank_cd normalization bitmask for the // LexicalSearch score. Bit 1 divides the rank by 1 + log(document length) so a diff --git a/pkg/platform/config.go b/pkg/platform/config.go index 8d21de2c4..25e3361d7 100644 --- a/pkg/platform/config.go +++ b/pkg/platform/config.go @@ -15,6 +15,7 @@ import ( "gopkg.in/yaml.v3" + "github.com/txn2/mcp-data-platform/internal/dbobs" "github.com/txn2/mcp-data-platform/internal/indexpolicy" "github.com/txn2/mcp-data-platform/internal/platform/configenv" "github.com/txn2/mcp-data-platform/internal/platform/configwarn" @@ -2050,7 +2051,7 @@ func (c *Config) Validate() error { _, runBudget := c.Scripts.Worker.RunMemoryBudget(0) _, thumbs := c.Thumbnails.Tuning() _, thumbSources := c.Thumbnails.SourceLimits() - for _, err := range []error{admission, runBudget, thumbs, thumbSources, c.Scripts.SQL.Validate(), c.Scripts.Draft.Validate(), c.Webhooks.Validate(), c.Resources.Index.Validate(), c.Tools.ResultBudget.Validate(), c.Portal.AssetRefs.Validate()} { + for _, err := range []error{admission, runBudget, thumbs, thumbSources, dbobs.CheckPoolSize(c.Database.MaxOpenConns), c.Scripts.SQL.Validate(), c.Scripts.Draft.Validate(), c.Webhooks.Validate(), c.Resources.Index.Validate(), c.Tools.ResultBudget.Validate(), c.Portal.AssetRefs.Validate()} { if err != nil { errs = append(errs, err.Error()) } diff --git a/pkg/platform/config_test.go b/pkg/platform/config_test.go index 5d0018aaa..24119b9dc 100644 --- a/pkg/platform/config_test.go +++ b/pkg/platform/config_test.go @@ -1253,6 +1253,20 @@ func TestConfigValidate_SessionsDatabaseWithoutDSN(t *testing.T) { } } +// #2169: a pool too small for the platform's background work is refused at +// startup, naming the minimum. +func TestConfigValidate_RefusesATooSmallPool(t *testing.T) { + cfg := &Config{Database: DatabaseConfig{DSN: "postgres://x", MaxOpenConns: 3}} + err := cfg.Validate() + if err == nil || !strings.Contains(err.Error(), "database.max_open_conns is 3; the platform needs at least 4") { + t.Errorf("Validate() with max_open_conns 3: %v", err) + } + cfg.Database.MaxOpenConns = 4 + if err := cfg.Validate(); err != nil { + t.Errorf("Validate() with max_open_conns 4: %v", err) + } +} + func TestConfigValidate_SessionsDatabaseWithDSN(t *testing.T) { cfg := &Config{ Sessions: SessionsConfig{ diff --git a/pkg/resource/foldersearch.go b/pkg/resource/foldersearch.go index d321bb3aa..e1b007eee 100644 --- a/pkg/resource/foldersearch.go +++ b/pkg/resource/foldersearch.go @@ -21,7 +21,7 @@ type ScoredFolder struct { } // folderFTS is the full-text expression a folder entry is matched on. -const folderFTS = "to_tsvector('english', path || ' ' || description || ' ' || summary_text)" +const folderFTS = "to_tsvector('english', fts_name_words(path) || ' ' || description || ' ' || summary_text)" // SearchFolders ranks the folder entries in the caller's visible libraries. // Only a folder that has an entry -- one holding files that are not indexed diff --git a/pkg/resource/search_realdb_integration_test.go b/pkg/resource/search_realdb_integration_test.go index 4743e4dbb..b7b00e46c 100644 --- a/pkg/resource/search_realdb_integration_test.go +++ b/pkg/resource/search_realdb_integration_test.go @@ -283,3 +283,49 @@ func TestResourceIndex_RealDB_UnsettledContentIsAGap(t *testing.T) { assert.Equal(t, []string{"res_owed"}, gaps, "an embedded row whose content pass never settled must still be a gap") } + +// TestResourceSearch_RealDB_AFileIsFoundByTheWordsOfItsName is #2230. Among +// thirty embedded files whose names look like it, one not embedded yet and +// named acceptance-1627-.csv is the first hit for "acceptance 1627 ": +// its name matches by its words, and an unembedded match outranks every file +// that matches none of the query's tokens. PostgreSQL's parser read the name +// as "acceptance" and the signed numbers -1627 and -, so the file matched +// nothing. A name with a dotted extension is found by its words the same way, +// and still by itself. +func TestResourceSearch_RealDB_AFileIsFoundByTheWordsOfItsName(t *testing.T) { + db := testdb.New(t) + store := NewPostgresStore(db) + ctx := context.Background() + insert := func(id, name string) { + require.NoError(t, store.Insert(ctx, Resource{ + ID: id, Scope: ScopeGlobal, Path: "acceptance-1657", Filename: name + ".bin", DisplayName: name, + MIMEType: "application/octet-stream", S3Key: id, URI: "mcp://global/acceptance-1657/" + name + ".bin", UploaderSub: "sub-1", + })) + } + for i := range 30 { + id := "res_alike_" + strings.Repeat("x", i+1) + insert(id, "Acceptance 1657 thing-"+strings.Repeat("a", i+1)) + _, err := db.ExecContext(ctx, `UPDATE resources SET embedding = $2, embedding_model = 'test' WHERE id = $1`, id, vectorLiteral(768)) + require.NoError(t, err) + } + const name = "acceptance-1627-1792487495133911000" + insert("res_target", name) + _, err := db.ExecContext(ctx, `UPDATE resources SET filename = 'q3-2024-report.csv' WHERE id = 'res_target'`) + require.NoError(t, err) + scopes := []ScopeFilter{{Scope: ScopeGlobal}} + + for _, query := range []string{"acceptance 1627 1792487495133911000", name, "q3 2024 report", "q3-2024-report.csv"} { + got, err := store.(Searcher).Search(ctx, SearchQuery{ + Embedding: unitQueryVector(768), //nolint:mnd // the schema's vector dimensionality + QueryText: query, Scopes: scopes, Limit: 25, + }) + require.NoError(t, err) + require.NotEmpty(t, got, query) + assert.Equal(t, "res_target", got[0].Resource.ID, "the first hit for %q", query) + + lexical, err := store.(Searcher).Search(ctx, SearchQuery{QueryText: query, Scopes: scopes}) + require.NoError(t, err) + require.NotEmpty(t, lexical, "the lexical search for %q", query) + assert.Equal(t, "res_target", lexical[0].Resource.ID, "the first lexical hit for %q", query) + } +} diff --git a/pkg/toolkits/portal/assetrefs.go b/pkg/toolkits/portal/assetrefs.go index a83476a76..83646dcb6 100644 --- a/pkg/toolkits/portal/assetrefs.go +++ b/pkg/toolkits/portal/assetrefs.go @@ -155,6 +155,30 @@ func (t *Toolkit) applyRefs( return len(refs), nil } +// widenRefs grants a write's newly declared references before its content +// write creates the version that makes the asset owed a tile (#2234): the tile +// worker may draw the new version the moment it exists, and a file not yet +// granted is drawn as missing and stays so until the next content change. +// undo puts the references back when that content write fails; applyRefs after +// a write that succeeded records exactly the declared set. +func (t *Toolkit) widenRefs( + ctx context.Context, assetID string, declared []assetrefs.Declared, present bool, +) (undo func(), result *mcp.CallToolResult) { + if !present { + return func() {}, nil + } + restore, err := t.contentRefs.Widen(ctx, assetID, declared, resolveOwnerEmail(ctx)) + if err != nil { + return nil, refResult(err) + } + return func() { + if err := restore(context.WithoutCancel(ctx)); err != nil { + slog.WarnContext(ctx, "portal: restoring an asset's references after a failed write", + "asset_id", assetID, "error", logsan.SanitizeForLog(err.Error())) + } + }, nil +} + // addRefFields reports a completed declaration on a map-shaped tool response. // A count below zero means the write said nothing about references, and adds // nothing. diff --git a/pkg/toolkits/portal/assetrefs_test.go b/pkg/toolkits/portal/assetrefs_test.go index d6068cfd1..1bc6ecdcf 100644 --- a/pkg/toolkits/portal/assetrefs_test.go +++ b/pkg/toolkits/portal/assetrefs_test.go @@ -3,6 +3,7 @@ package portal import ( "context" "encoding/json" + "errors" "fmt" "testing" @@ -605,3 +606,179 @@ func TestSaveRecordsReferencesBeforeTheFirstVersion(t *testing.T) { out := decodeSave(t, result) assert.Equal(t, 1, versions.atNew[out.AssetID], "the reference was not recorded when the first version was created") } + +// refsRig is a toolkit whose version store notes how many references an asset +// had when each version was created, with an asset saved naming the logo. +type refsRig struct { + tk *Toolkit + versions *refsAtVersionStore + refs *refStoreStub + s3 *mockS3Client + id string +} + +func versionRefsRig(t *testing.T) refsRig { + t.Helper() + assets := newInMemoryAssetStore() + refs := newRefStoreStub() + versions := &refsAtVersionStore{inMemoryVersionStore: newInMemoryVersionStore(), refs: refs, atNew: map[string]int{}} + s3 := &mockS3Client{getBody: []byte("

Q4

"), getCT: "text/html"} + tk := New(Config{ + Name: "test", AssetStore: assets, VersionStore: versions, + S3Client: s3, S3Bucket: "bucket", BaseURL: "http://example.com", + }) + tk.SetContentRefs(newDeclarer(refs, assets)) + saved := decodeSave(t, mustSave(t, tk, []string{refLogoURI})) + return refsRig{tk: tk, versions: versions, refs: refs, s3: s3, id: saved.AssetID} +} + +// TestUpdateGrantsNewReferencesBeforeTheNewVersion is #2234: the new version +// is what makes the asset owed a tile, so a reference the update declares is +// already recorded when it is created, beside the one the update drops, which +// the content still current until then uses; once the content is written the +// asset names exactly what the update declared, the kept reference with its +// token. +func TestUpdateGrantsNewReferencesBeforeTheNewVersion(t *testing.T) { + rig := versionRefsRig(t) + tk, versions, refs, id := rig.tk, rig.versions, rig.refs, rig.id + logoToken := refs.byAsset[id][0].RefToken + + result, _, err := tk.handleUpdate(refCtx("finance"), manageAssetInput{ + Action: "update", AssetID: id, Content: ``, + References: []string{refChartURI}, + }) + require.NoError(t, err) + require.False(t, result.IsError, errText(t, result)) + assert.Equal(t, 2, versions.atNew[id], "the new reference was not recorded when the version was created") + stored := refs.byAsset[id] + require.Len(t, stored, 1) + assert.Equal(t, "res-chart", stored[0].TargetID) + + result, _, err = tk.handleUpdate(refCtx("finance"), manageAssetInput{ + Action: "update", AssetID: id, Content: ``, + References: []string{refLogoURI, refChartURI}, + }) + require.NoError(t, err) + require.False(t, result.IsError, errText(t, result)) + assert.Equal(t, 2, versions.atNew[id]) + require.Len(t, refs.byAsset[id], 2) + chartToken := refs.byAsset[id][1].RefToken + assert.NotEqual(t, logoToken, refs.byAsset[id][0].RefToken, "a reference dropped and declared again is a new grant") + + // Content that names what the asset already has adds nothing first. + result, _, err = tk.handleUpdate(refCtx("finance"), manageAssetInput{ + Action: "update", AssetID: id, Content: ``, References: []string{refChartURI}, + }) + require.NoError(t, err) + require.False(t, result.IsError, errText(t, result)) + require.Len(t, refs.byAsset[id], 1) + assert.Equal(t, chartToken, refs.byAsset[id][0].RefToken, "a kept reference keeps its token") +} + +// TestPatchGrantsNewReferencesBeforeTheNewVersion is #2234 for a patch. +func TestPatchGrantsNewReferencesBeforeTheNewVersion(t *testing.T) { + rig := versionRefsRig(t) + tk, versions, refs, id := rig.tk, rig.versions, rig.refs, rig.id + result, _, err := tk.handlePatch(refCtx("finance"), manageAssetInput{ + Action: "patch", AssetID: id, + Edits: []textpatch.Edit{{Op: textpatch.OpInsertAfter, Find: "

", Text: ``}}, + References: []string{refLogoURI, refChartURI}, + }) + require.NoError(t, err) + require.False(t, result.IsError, errText(t, result)) + assert.Equal(t, 2, versions.atNew[id], "the new reference was not recorded when the version was created") + assert.Len(t, refs.byAsset[id], 2) +} + +// TestAFailedContentWriteRestoresTheReferences: a write whose content could not +// be stored leaves the asset naming what it named before, not the references +// granted ahead of it. +func TestAFailedContentWriteRestoresTheReferences(t *testing.T) { + for _, action := range []string{"update", "patch"} { + t.Run(action, func(t *testing.T) { + rig := versionRefsRig(t) + tk, refs, s3, id := rig.tk, rig.refs, rig.s3, rig.id + s3.putErr = errors.New("storage down") + input := manageAssetInput{Action: action, AssetID: id, References: []string{refChartURI}} + var ( + result *mcp.CallToolResult + err error + ) + if action == "update" { + input.Content = `` + result, _, err = tk.handleUpdate(refCtx("finance"), input) + } else { + input.Edits = []textpatch.Edit{{Op: textpatch.OpInsertAfter, Find: "", Text: ``}} + result, _, err = tk.handlePatch(refCtx("finance"), input) + } + require.NoError(t, err) + require.True(t, result.IsError) + stored := refs.byAsset[id] + require.Len(t, stored, 1) + assert.Equal(t, "res-logo", stored[0].TargetID) + }) + } +} + +// failingRefs is a reference store that fails its reads once told to, and its +// writes after replacesOK more have succeeded (negative: never). +type failingRefs struct { + *refStoreStub + listErr error + replacesOK int +} + +func (f *failingRefs) ListByAsset(ctx context.Context, id string) ([]assetrefs.Ref, error) { + if f.listErr != nil { + return nil, f.listErr + } + return f.refStoreStub.ListByAsset(ctx, id) +} + +func (f *failingRefs) Replace(ctx context.Context, id string, refs []assetrefs.Ref) error { + if f.replacesOK == 0 { + return errors.New("refs down") + } + f.replacesOK-- + return f.refStoreStub.Replace(ctx, id, refs) +} + +// A write whose references cannot be granted ahead of it changes nothing and +// says so; a failed content write whose references cannot be put back is +// still reported as the content write's failure (#2234). +func TestWidenFailures(t *testing.T) { + assets := newInMemoryAssetStore() + refs := &failingRefs{refStoreStub: newRefStoreStub(), replacesOK: -1} + s3 := &mockS3Client{getBody: []byte("

Q4

"), getCT: "text/html"} + tk := New(Config{ + Name: "test", AssetStore: assets, VersionStore: newInMemoryVersionStore(), + S3Client: s3, S3Bucket: "bucket", BaseURL: "http://example.com", + }) + tk.SetContentRefs(newDeclarer(refs, assets)) + id := decodeSave(t, mustSave(t, tk, []string{refLogoURI})).AssetID + update := manageAssetInput{ + Action: "update", AssetID: id, Content: ``, References: []string{refChartURI}, + } + + refs.listErr = errors.New("refs down") + result, _, err := tk.handleUpdate(refCtx("finance"), update) + require.NoError(t, err) + require.True(t, result.IsError, "a grant that could not be recorded refuses the write") + + refs.listErr = nil + s3.putErr = errors.New("storage down") + result, _, err = tk.handleUpdate(refCtx("finance"), update) + require.NoError(t, err) + require.True(t, result.IsError) + assert.Contains(t, errText(t, result), "failed to upload new content") + + // The grant ahead of the write is recorded; putting it back is not. + refs.replacesOK = 1 + result, _, err = tk.handlePatch(refCtx("finance"), manageAssetInput{ + Action: "patch", AssetID: id, References: []string{refChartURI}, + Edits: []textpatch.Edit{{Op: textpatch.OpInsertAfter, Find: "", Text: "

x

"}}, + }) + require.NoError(t, err) + require.True(t, result.IsError) + assert.Contains(t, errText(t, result), "failed to write patched content") +} diff --git a/pkg/toolkits/portal/patch_handlers.go b/pkg/toolkits/portal/patch_handlers.go index 871ecdc60..eb0bb5ba5 100644 --- a/pkg/toolkits/portal/patch_handlers.go +++ b/pkg/toolkits/portal/patch_handlers.go @@ -155,6 +155,10 @@ func (t *Toolkit) handlePatch(ctx context.Context, input manageAssetInput) (*mcp return toolkit.JSONResultTyped(result) } + undo, widenResult := t.widenRefs(ctx, asset.ID, declaredRefs, hasRefs) + if widenResult != nil { + return widenResult, nil, nil + } version, tables, err := t.uploadContentUpdate(ctx, asset, contentEdit{ content: res.Body, declaredType: asset.ContentType, @@ -162,6 +166,7 @@ func (t *Toolkit) handlePatch(ctx context.Context, input manageAssetInput) (*mcp sources: input.Sources, }) if err != nil { + undo() return toolkit.ErrorResult("failed to write patched content: " + err.Error()), nil, nil } refCount, applyResult := t.applyRefs(ctx, asset.ID, declaredRefs, hasRefs) diff --git a/pkg/toolkits/portal/toolkit.go b/pkg/toolkits/portal/toolkit.go index c8981e296..4c70cb284 100644 --- a/pkg/toolkits/portal/toolkit.go +++ b/pkg/toolkits/portal/toolkit.go @@ -1050,6 +1050,10 @@ func (t *Toolkit) handleUpdate(ctx context.Context, input manageAssetInput) (*mc var followed map[string]any if hasContent { + undo, widenResult := t.widenRefs(ctx, asset.ID, declaredRefs, hasRefs) + if widenResult != nil { + return widenResult, nil, nil + } edit := contentEdit{ content: input.Content, declaredType: input.ContentType, @@ -1058,6 +1062,7 @@ func (t *Toolkit) handleUpdate(ctx context.Context, input manageAssetInput) (*mc } version, tables, contentErr := t.uploadContentUpdate(ctx, asset, edit) if contentErr != nil { + undo() return toolkit.ErrorResult("failed to upload new content: " + contentErr.Error()), nil, nil } followed = tableFields(version, tables) diff --git a/scripts/docs-image-digests.sh b/scripts/docs-image-digests.sh new file mode 100755 index 000000000..c3d55790c --- /dev/null +++ b/scripts/docs-image-digests.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Resolve every image the documentation pins to a digest (#2224). +# +# A digest written in the docs is checked by nothing else: three counting +# patterns (sha256:acf5271b...e1f2a3b) shipped in the deployment guide's +# compose example, and anyone who copied it got "manifest unknown". This asks +# each image's registry for the digest as written and fails on one it does not +# serve. It needs network access and Docker, so it runs in the E2E Nightly, +# not in verify. +# +# Usage: docs-image-digests.sh [dir] (default: docs) +# Prints one line per image that does not resolve and exits 1 when there is one. +set -eu + +dir=${1:-docs} +refs=$(grep -rhoE '[a-z0-9][a-z0-9./_-]*(:[A-Za-z0-9._-]+)?@sha256:[0-9a-zA-Z]+' "$dir" | sort -u) +if [ -z "$refs" ]; then + echo "docs-image-digests: no image pinned to a digest under $dir" + exit 0 +fi + +failed=0 +for ref in $refs; do + digest=${ref##*@sha256:} + if ! printf '%s' "$digest" | grep -qE '^[0-9a-f]{64}$'; then + echo "docs-image-digests: $ref: a digest is 64 lowercase hex characters" + failed=1 + continue + fi + if ! docker buildx imagetools inspect "$ref" >/dev/null 2>&1; then + echo "docs-image-digests: $ref: the registry does not serve this digest" + failed=1 + continue + fi + echo "docs-image-digests: $ref" +done +exit $failed diff --git a/test/acceptance/issue_1627_test.go b/test/acceptance/issue_1627_test.go index 839a281a6..b084305a2 100644 --- a/test/acceptance/issue_1627_test.go +++ b/test/acceptance/issue_1627_test.go @@ -231,11 +231,9 @@ func objects1627(t *testing.T, raw []any) []map[string]any { func hitTable1627(t *testing.T, c *client, reference, name string) map[string]any { t.Helper() intent := strings.ReplaceAll(name, "-", " ") - // A file is ranked by its embedding beside its words, and one not yet - // embedded is outranked by files whose names merely look alike: a stack - // holding hundreds of acceptance files buried it below the limit. What - // this criterion reads is the hit's table, so it searches once the file's - // index job has finished. + // What this criterion reads is the hit's table, which the file's index + // job records, so it searches once that job has finished. The file is + // found by the words of its name (#2230). db := issue1904DB(t) id := strings.TrimPrefix(reference, "mcp:resource:") issue1904Await(t, "the file's index job finished", func() bool { diff --git a/test/acceptance/issue_2169_test.go b/test/acceptance/issue_2169_test.go new file mode 100644 index 000000000..9a3fd5308 --- /dev/null +++ b/test/acceptance/issue_2169_test.go @@ -0,0 +1,171 @@ +//go:build integration + +package acceptance + +import ( + "context" + "database/sql" + "fmt" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + "testing" + "time" +) + +// Acceptance for #2169: a replica held its background locks on a pooled +// connection each, and once the locks outnumbered the free connections it +// served nothing that read the database while /readyz said 200. Every +// try-lock the platform holds across work now shares one session per process. +// A replica holding more locks than its pool has connections keeps one of +// them for all of the locks and goes on answering search, admin reads and +// /readyz; and a pool smaller than the platform's minimum is refused at +// startup, naming the minimum. +// +// The locks are connlimit slots: they are the locks a caller can hold for as +// long as it likes, a slot per call in flight on a connection with +// max_concurrent_calls. The background loops' locks are the same lock on the +// same session, held for as long as a pass runs, and +// internal/advisorylock's RealDB tests hold the loops' own together. +// +// Wire forms: the connection's max_concurrent_calls is sent to the admin API +// as a JSON number; api_invoke_endpoint's query_params is a typed object and +// timeout_seconds a typed integer; search's intent and purpose are strings. The startup +// refusal is the configuration file's database.max_open_conns, a YAML +// integer. + +const ( + // issue2169Slots is more slots than a dev replica's pool (10) has + // connections, so a session per slot would hold every one of them. + issue2169Slots = 15 + // issue2169Hold is how long each call holds its slot, in milliseconds. + issue2169Hold = 6000 + // issue2169Answer bounds a request the replica serves while the slots are + // held. + issue2169Answer = 3 * time.Second + // issue2169Purpose is the sentence each search states. + issue2169Purpose = "Acceptance #2169: a replica holding many locks keeps serving." +) + +// issue2169SlotHolders counts the granted two-integer advisory locks (the +// form a slot takes) on the dev database and the sessions holding them. +func issue2169SlotHolders(t *testing.T, db *sql.DB) (locks, sessions int) { + t.Helper() + err := db.QueryRowContext(t.Context(), ` + SELECT count(*), count(DISTINCT pid) FROM pg_locks + WHERE locktype = 'advisory' AND objsubid = 2 AND granted + AND database = (SELECT oid FROM pg_database WHERE datname = current_database())`).Scan(&locks, &sessions) + if err != nil { + t.Fatalf("reading the held advisory locks: %v", err) + } + return locks, sessions +} + +// issue2169Timed runs fn and fails when it takes longer than the bound. +func issue2169Timed(t *testing.T, what string, fn func()) { + t.Helper() + start := time.Now() + fn() + if took := time.Since(start); took > issue2169Answer { + t.Errorf("%s took %s while the replica held %d slots; the bound is %s", what, took, issue2169Slots, issue2169Answer) + } +} + +// TestIssue2169_AReplicaHoldingMoreLocksThanConnectionsKeepsServing: fifteen +// calls in flight through one replica on a connection limited to fifteen hold +// fifteen slots on one database session, and the replica answers search, an +// admin read and /readyz within the bound while they do. With a session per +// slot the fifteen needed fifteen of the replica's ten connections, and +// nothing else on it was served until they finished. +func TestIssue2169_AReplicaHoldingMoreLocksThanConnectionsKeepsServing(t *testing.T) { + target := replicas(t)[0] + c := connectAtFor(t, target.base, devAPIKey(), 3*time.Minute) + db := devDB(t) + name := issue2209Connection(t, c, "2169-slots", issue2169Slots) + c.call("search", map[string]any{"intent": "acceptance 2169: a replica holding many locks", "purpose": issue2169Purpose}) + + before, _ := issue2169SlotHolders(t, db) + var wg sync.WaitGroup + failures := make(chan string, issue2169Slots) + for range issue2169Slots { + wg.Go(func() { + if text, ok := issue2209Slow(c, name, issue2169Hold, 60); !ok { + failures <- text + } + }) + } + + deadline := time.Now().Add(issue2169Hold * time.Millisecond / 2) + var locks, sessions int + for time.Now().Before(deadline) { + if locks, sessions = issue2169SlotHolders(t, db); locks-before >= issue2169Slots { + break + } + time.Sleep(100 * time.Millisecond) + } + if locks-before < issue2169Slots { + t.Fatalf("%d slots held after %s; the criterion needs all %d in flight at once", locks-before, issue2169Hold*time.Millisecond/2, issue2169Slots) + } + if sessions > 1 { + t.Errorf("%d slots are held by %d database sessions; a replica holds its locks on one", locks, sessions) + } + + issue2169Timed(t, "search", func() { + c.call("search", map[string]any{"intent": "acceptance 2169: served while the slots are held", "purpose": issue2169Purpose}) + }) + issue2169Timed(t, "an admin read", func() { + if status, out := c.rest(http.MethodGet, "/api/v1/admin/connection-instances", nil); status != http.StatusOK { + t.Errorf("GET /api/v1/admin/connection-instances: HTTP %d: %v", status, out) + } + }) + issue2169Timed(t, "/readyz", func() { + ctx, cancel := context.WithTimeout(t.Context(), issue2169Answer) + defer cancel() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, target.base+"/readyz", http.NoBody) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Fatal(err) + } + res, err := http.DefaultClient.Do(req) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Errorf("/readyz: %v", err) + return + } + _ = res.Body.Close() //nolint:errcheck // only the status is read + if res.StatusCode != http.StatusOK { + t.Errorf("/readyz answered %d", res.StatusCode) + } + }) + + wg.Wait() + close(failures) + for f := range failures { + t.Errorf("a call holding a slot failed: %s", f) + } +} + +// TestIssue2169_APoolBelowTheMinimumIsRefusedAtStartup: the platform started +// with database.max_open_conns 3 exits before it opens anything, naming the +// value and the minimum of 4. +func TestIssue2169_APoolBelowTheMinimumIsRefusedAtStartup(t *testing.T) { + bin := platformBinary(t) + cfg := filepath.Join(t.TempDir(), "platform.yaml") + body := fmt.Sprintf("server:\n name: acc-2169\n transport: stdio\ndatabase:\n dsn: %q\n max_open_conns: 3\n", issue1694DevDSN()) + if err := os.WriteFile(cfg, []byte(body), 0o600); err != nil { + t.Fatal(err) + } + ctx, cancel := context.WithTimeout(t.Context(), time.Minute) + defer cancel() + out, err := exec.CommandContext(ctx, bin, "--config", cfg).CombinedOutput() // #nosec G204 -- the binary this tree built, with a config this test wrote + if err == nil { + t.Fatalf("the platform started with max_open_conns 3:\n%s", out) + } + if ctx.Err() != nil { + t.Fatalf("the platform did not exit within a minute of starting with max_open_conns 3:\n%s", out) + } + if want := "database.max_open_conns is 3; the platform needs at least 4"; !strings.Contains(string(out), want) { + t.Errorf("the refusal does not say %q:\n%s", want, out) + } +} diff --git a/test/acceptance/issue_2203_test.go b/test/acceptance/issue_2203_test.go new file mode 100644 index 000000000..f09d25778 --- /dev/null +++ b/test/acceptance/issue_2203_test.go @@ -0,0 +1,218 @@ +//go:build integration + +package acceptance + +import ( + "encoding/json" + "io" + "math" + "net/http" + "strconv" + "strings" + "testing" + "time" +) + +// Acceptance for #2203: a fresh install's setup was fitted as growth and +// shown as a fill date. A store's first day is now left out of every fit, a +// 30-day rate waits for two weeks of history after it, and each tick is +// sampled by one replica: the other finds the sample and skips. +// +// Wire forms: this ticket adds no tool parameter. GET +// /api/v1/admin/storage takes no parameter; GET /api/v1/admin/storage/history +// takes store and days as query strings, the one form a query has. + +// issue2203Interval is the dev stack's storage sampling interval, the +// default. +const issue2203Interval = 15 * time.Minute + +// issue2203Point is one stored sample as the history route answers it. +type issue2203Point struct { + At time.Time `json:"at"` + Used int64 `json:"used_bytes"` +} + +// issue2203Report is the part of the storage report the criteria read. +type issue2203Report struct { + GeneratedAt time.Time `json:"generated_at"` + Stores []struct { + Store string `json:"store"` + Used int64 `json:"used_bytes"` + History float64 `json:"history_hours"` + Rate7d *float64 `json:"rate_7d_bytes_per_day"` + Rate30d *float64 `json:"rate_30d_bytes_per_day"` + Min7d float64 `json:"rate_7d_min_history_hours"` + Min30d float64 `json:"rate_30d_min_history_hours"` + ExhaustedAt *string `json:"exhaustion_at"` + } `json:"stores"` +} + +// issue2203Get reads one admin route as the suite's administrator. +func issue2203Get(t *testing.T, c *client, path string, into any) { + t.Helper() + req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, c.base+path, http.NoBody) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer "+c.apiKey) + res, err := http.DefaultClient.Do(req) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Fatalf("GET %s: %v", path, err) + } + defer res.Body.Close() //nolint:errcheck // best-effort close after read + raw, _ := io.ReadAll(res.Body) + if res.StatusCode != http.StatusOK { + t.Fatalf("GET %s: HTTP %d: %s", path, res.StatusCode, raw) + } + if err := json.Unmarshal(raw, into); err != nil { + t.Fatalf("GET %s: %v\n%s", path, err, raw) + } +} + +// issue2203Slope is the least-squares slope of used bytes over the points at +// or after from, in bytes per day; ok is false with fewer than two. +func issue2203Slope(points []issue2203Point, from time.Time) (slope float64, ok bool) { + var in []issue2203Point + for _, p := range points { + if !p.At.Before(from) { + in = append(in, p) + } + } + if len(in) < 2 { + return 0, false + } + x := func(p issue2203Point) float64 { return p.At.Sub(in[0].At).Hours() / 24 } + var mx, my float64 + for _, p := range in { + mx += x(p) + my += float64(p.Used) + } + n := float64(len(in)) + mx, my = mx/n, my/n + var sxx, sxy float64 + for _, p := range in { + sxx += (x(p) - mx) * (x(p) - mx) + sxy += (x(p) - mx) * (float64(p.Used) - my) + } + return sxy / sxx, sxx > 0 +} + +// TestIssue2203_TheFitLeavesTheStoresFirstDayOut: the database's weekly rate +// on the admin storage report is the fit of its samples from the end of its +// first day, not from its first sample; each rate names the history it needs +// counting that first day; and a store with less than that has no rate. +func TestIssue2203_TheFitLeavesTheStoresFirstDayOut(t *testing.T) { + c := connect(t) + var report issue2203Report + issue2203Get(t, c, "/api/v1/admin/storage", &report) + var history struct { + Points []issue2203Point `json:"points"` + } + issue2203Get(t, c, "/api/v1/admin/storage/history?store=database&days=30", &history) + + for _, s := range report.Stores { + if s.Store != "database" { + continue + } + if s.Min7d != 48 || s.Min30d != 360 { + t.Errorf("a store whose whole history is kept needs 48 h for a weekly rate and 360 h for a monthly one; the report says %v and %v", s.Min7d, s.Min30d) + } + if s.History < s.Min7d { + if s.Rate7d != nil || s.ExhaustedAt != nil { + t.Errorf("%.1f h of history, short of %v, and the report gives a rate %v and a fill date %v", s.History, s.Min7d, s.Rate7d, s.ExhaustedAt) + } + return + } + if s.History < s.Min30d && s.Rate30d != nil { + t.Errorf("%.1f h of history, short of %v, and the report gives a monthly rate", s.History, s.Min30d) + } + var points []issue2203Point + for _, p := range history.Points { + if p.At.Before(report.GeneratedAt) { + points = append(points, p) + } + } + points = append(points, issue2203Point{At: report.GeneratedAt, Used: s.Used}) + from := points[0].At.Add(24 * time.Hour) + if week := report.GeneratedAt.Add(-7 * 24 * time.Hour); week.After(from) { + from = week + } + want, ok := issue2203Slope(points, from) + if !ok || s.Rate7d == nil { + t.Fatalf("the report's weekly rate %v, and %d samples after the first day", s.Rate7d, len(points)) + } + withSetup, _ := issue2203Slope(points, points[0].At) + t.Logf("database: weekly rate %.0f B/day reported, %.0f B/day fitted from the end of the first day, %.0f B/day fitted from the first sample", *s.Rate7d, want, withSetup) + if math.Abs(*s.Rate7d-want) > math.Max(math.Abs(want)*0.01, 1) { + t.Errorf("the weekly rate is %.0f B/day; fitted from the end of the store's first day it is %.0f", *s.Rate7d, want) + } + return + } + t.Fatal("the storage report names no database store") +} + +// issue2203Scrape reads one replica's metrics and returns the value of the +// unlabeled series name, and of name with the given label text. +func issue2203Scrape(t *testing.T, url, line string) float64 { + t.Helper() + req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, url, http.NoBody) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Fatal(err) + } + res, err := http.DefaultClient.Do(req) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Fatalf("GET %s: %v", url, err) + } + defer res.Body.Close() //nolint:errcheck // best-effort close after read + raw, _ := io.ReadAll(res.Body) + for l := range strings.SplitSeq(string(raw), "\n") { + if strings.HasPrefix(l, line+" ") { + v, err := strconv.ParseFloat(strings.TrimSpace(strings.TrimPrefix(l, line)), 64) + if err == nil { + return v + } + } + } + return 0 +} + +// TestIssue2203_EachTickIsSampledByOneReplica: since the replicas started, +// no two database samples lie within one sampling tick of each other, and a +// replica that found the other's sample counted its pass as skipped. Each +// replica runs a pass as it starts, so two replicas started together sampled +// the same tick twice before. +func TestIssue2203_EachTickIsSampledByOneReplica(t *testing.T) { + c := connect(t) + urls := metricsURLs() + if len(urls) < 2 { + t.Fatal("this criterion reads both replicas' metrics: run `make dev` with two replicas, or set ACCEPTANCE_METRICS_URL to both") + } + var started time.Time + var skipped float64 + for _, u := range urls { + start := time.Unix(int64(issue2203Scrape(t, u, "process_start_time_seconds")), 0) + if started.IsZero() || start.Before(started) { + started = start + } + skipped += issue2203Scrape(t, u, `background_loop_iterations_total{loop="storage_history",result="skipped"}`) + } + var history struct { + Points []issue2203Point `json:"points"` + } + issue2203Get(t, c, "/api/v1/admin/storage/history?store=database&days=1", &history) + var since []issue2203Point + for _, p := range history.Points { + if !p.At.Before(started) { + since = append(since, p) + } + } + for i := 1; i < len(since); i++ { + if gap := since[i].At.Sub(since[i-1].At); gap < issue2203Interval*9/10 { + t.Errorf("samples at %s and %s, %s apart: one tick sampled twice", since[i-1].At, since[i].At, gap) + } + } + if skipped < 1 { + t.Errorf("no replica skipped a pass since %s; with two replicas each starting with a pass, one finds the other's sample", started) + } + t.Logf("%d database samples since the replicas started at %s; %v passes skipped", len(since), started, skipped) +} diff --git a/test/acceptance/issue_2230_test.go b/test/acceptance/issue_2230_test.go new file mode 100644 index 000000000..947f2e2c5 --- /dev/null +++ b/test/acceptance/issue_2230_test.go @@ -0,0 +1,120 @@ +//go:build integration + +package acceptance + +import ( + "encoding/base64" + "fmt" + "net/http" + "strings" + "testing" + "time" + + "github.com/lib/pq" +) + +// Acceptance for #2230: a file searched for by the words of its own name was +// missing from the answer, behind files whose names only looked alike. +// PostgreSQL's parser read "acceptance-1627-1792487495133911000" as the word +// "acceptance" and the signed numbers -1627 and -1792487495133911000, so a +// search for "acceptance 1627 1792487495133911000" never matched it, and a +// file not yet embedded had nothing else to be found by. A name is now +// matched by its words on every full-text surface, and an operation not yet +// embedded is blended as the SQL rankers blend a row the vector arm cannot +// see. +// +// Wire forms: search's intent is a string and sources a list of strings; +// manage_resource's content_base64, filename, display_name and path are +// strings; save_asset's name, content and content_type are strings. Each is +// sent as literal params. + +const ( + issue2230Alike = 30 + issue2230Purpose = "Acceptance #2230: a file is found by the words of its name." +) + +// issue2230Upload uploads a small file under acceptance-2230 named name and +// returns its reference. +func issue2230Upload(t *testing.T, c *client, name string) string { + t.Helper() + out := c.call("manage_resource", map[string]any{ + "action": "create", "filename": name + ".bin", "display_name": name, "path": "acceptance-2230", + "description": "Acceptance #2230.", + "content_base64": base64.StdEncoding.EncodeToString([]byte("acceptance 2230 " + name)), + "content_type": "application/octet-stream", + }) + id, _ := out["resource_id"].(string) + if id == "" { + t.Fatalf("manage_resource create returned no resource_id: %v", out) + } + t.Cleanup(func() { _, _ = c.rest(http.MethodDelete, "/api/v1/resources/"+id, http.NoBody) }) + return "mcp:resource:" + id +} + +// issue2230First returns the reference of the first hit search answers for +// intent in one source. +func issue2230First(t *testing.T, c *client, intent, source string) string { + t.Helper() + out := c.call("search", map[string]any{ + "intent": intent, "sources": []any{source}, "limit": 25, "purpose": issue2230Purpose, + }) + groups, _ := out["groups"].([]any) + for _, group := range groups { + g, _ := group.(map[string]any) + hits, _ := g["hits"].([]any) + if len(hits) > 0 { + first, _ := hits[0].(map[string]any) + ref, _ := first["reference"].(string) + return ref + } + } + return "" +} + +// TestIssue2230_AFileIsFoundByTheWordsOfItsName: among thirty embedded files +// named alike, a file uploaded a moment ago and named +// acceptance-2230- is the first resource search answers for +// "acceptance 2230 ", before its own embedding lands. +func TestIssue2230_AFileIsFoundByTheWordsOfItsName(t *testing.T) { + c := connectFor(t, 5*time.Minute) + db := issue1904DB(t) + stamp := time.Now().UnixNano() + var alike []string + for i := range issue2230Alike { + ref := issue2230Upload(t, c, fmt.Sprintf("acceptance-2230-thing-%d-%d", stamp, i)) + alike = append(alike, strings.TrimPrefix(ref, "mcp:resource:")) + } + issue1904Await(t, "the alike files are embedded", func() bool { + return issue1904Count(t, db, `SELECT COUNT(*) FROM resources WHERE id = ANY($1) AND embedding IS NOT NULL`, pq.Array(alike)) == issue2230Alike + }) + + name := fmt.Sprintf("acceptance-2230-%d", stamp+1) + target := issue2230Upload(t, c, name) + if got := issue2230First(t, c, strings.ReplaceAll(name, "-", " "), "resources"); got != target { + t.Errorf("the first resource for %q is %s; want the file named so, %s", strings.ReplaceAll(name, "-", " "), got, target) + } + if got := issue2230First(t, c, name, "resources"); got != target { + t.Errorf("the first resource for its own name %q is %s; want %s", name, got, target) + } +} + +// TestIssue2230_AnAssetIsFoundByTheWordsOfItsName: a saved asset named +// q3-2024--report is the first asset search answers for +// "q3 2024 report". +func TestIssue2230_AnAssetIsFoundByTheWordsOfItsName(t *testing.T) { + c := connect(t) + name := fmt.Sprintf("q3-2024-%d-report", time.Now().UnixNano()) + saved := c.call("save_asset", map[string]any{ + "name": name, "content": "

Q3

", "content_type": "text/html", + "description": "Acceptance #2230: an asset found by the words of its name.", + }) + id, _ := saved["asset_id"].(string) + if id == "" { + t.Fatalf("save_asset returned no asset_id: %v", saved) + } + t.Cleanup(func() { _, _, _ = c.callRaw("manage_asset", map[string]any{"action": "delete", "asset_id": id}) }) + intent := strings.ReplaceAll(name, "-", " ") + if got := issue2230First(t, c, intent, "assets"); got != "mcp:asset:"+id { + t.Errorf("the first asset for %q is %s; want mcp:asset:%s", intent, got, id) + } +} diff --git a/test/acceptance/issue_2231_test.go b/test/acceptance/issue_2231_test.go new file mode 100644 index 000000000..22dde8d5f --- /dev/null +++ b/test/acceptance/issue_2231_test.go @@ -0,0 +1,79 @@ +//go:build integration + +package acceptance + +import ( + "encoding/json" + "io" + "net/http" + "testing" + "time" +) + +// Acceptance for #2231: filtering the call list by outcome took 36 seconds on +// a catalog of about 95,000 records, because the outcome was derived per +// record. Each outcome now answers within a second, on the admin list and on +// the portal's own list. +// +// Wire forms: this ticket adds no tool parameter. GET /api/v1/admin/calls and +// GET /api/v1/portal/calls take outcome and per_page as query strings, the one +// form a query takes. + +// issue2231Bound is the time one filtered page and its total may take. +const issue2231Bound = time.Second + +// issue2231Page reads one page of a call list and returns its total and how +// long the request took. +func issue2231Page(t *testing.T, c *client, path string) (total int, took time.Duration) { + t.Helper() + req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, c.base+path, http.NoBody) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer "+c.apiKey) + start := time.Now() + res, err := http.DefaultClient.Do(req) // #nosec G704 -- the platform under test, named by the suite's own environment + if err != nil { + t.Fatalf("GET %s: %v", path, err) + } + defer res.Body.Close() //nolint:errcheck // best-effort close after read + raw, _ := io.ReadAll(res.Body) + took = time.Since(start) + if res.StatusCode != http.StatusOK { + t.Fatalf("GET %s: HTTP %d: %s", path, res.StatusCode, raw) + } + var page struct { + Total int `json:"total"` + } + if err := json.Unmarshal(raw, &page); err != nil { + t.Fatalf("GET %s: %v", path, err) + } + return page.Total, took +} + +// TestIssue2231_EachOutcomeAnswersWithinASecond: on the dev catalog, each +// outcome filter on the admin call list and on the portal's own answers within +// a second, and the outcomes' totals add up to the unfiltered total, read +// before and after them. +func TestIssue2231_EachOutcomeAnswersWithinASecond(t *testing.T) { + c := connect(t) + for _, list := range []string{"/api/v1/admin/calls", "/api/v1/portal/calls"} { + // The dev stack records calls while this runs, so the outcomes are + // held between the totals read before and after them. + before, _ := issue2231Page(t, c, list+"?per_page=50") + sum := 0 + for _, outcome := range []string{"failed", "satisfied", "superseded", "ran"} { + total, took := issue2231Page(t, c, list+"?per_page=50&outcome="+outcome) + t.Logf("%s outcome=%s: %d records in %s", list, outcome, total, took) + if took > issue2231Bound { + t.Errorf("%s filtered to %s took %s; the bound is %s", list, outcome, took, issue2231Bound) + } + sum += total + } + after, _ := issue2231Page(t, c, list+"?per_page=50") + t.Logf("%s: %d records before the outcomes were read, %d after", list, before, after) + if sum < before || sum > after { + t.Errorf("%s: the outcomes total %d, outside the list's %d to %d", list, sum, before, after) + } + } +} diff --git a/test/acceptance/issue_2234_test.go b/test/acceptance/issue_2234_test.go new file mode 100644 index 000000000..15dbccd5e --- /dev/null +++ b/test/acceptance/issue_2234_test.go @@ -0,0 +1,100 @@ +//go:build integration + +package acceptance + +import ( + "encoding/base64" + "net/http" + "os" + "testing" + "time" +) + +// #2234: manage_asset update and patch created the new version, which makes +// the asset owed a tile, before they recorded the references the write +// declared, so the tile worker could draw the new version while a newly +// declared file was still refused, and keep that tile until the next content +// change. The references a write declares are now granted before its version +// exists. +// +// Each criterion starts from an asset drawn without the font, and writes the +// #2062 page that declares it: the tile of the new version is the page's +// font-loaded color. +// +// Wire forms: manage_asset update's content is a string and references a list +// of strings; manage_asset patch's edits is a list of objects (op, find, +// replace as strings) and references a list of strings. Each is sent once, as +// literal params. + +// plainPage2234 is the page an asset starts as: one color, no reference. +const plainPage2234 = `export default function App() { + return
; +} +` + +// fontURI2234 uploads the #2062 font as a managed resource and saves an +// asset as the plain page, drawn; it returns the asset's id and the font's URI. +func fontURI2234(t *testing.T, c *client) (assetID, uri string) { + t.Helper() + font, err := os.ReadFile("testdata/issue_2062_font.woff2") + if err != nil { + t.Fatalf("reading the font fixture: %v", err) + } + name := "acceptance-2234-" + unique1794() + out := c.call("manage_resource", map[string]any{ + "action": "create", "filename": name + ".woff2", "display_name": name, "path": "acceptance-2234", + "description": "Acceptance #2234: a brand font an update declares.", + "content_base64": base64.StdEncoding.EncodeToString(font), + "content_type": "font/woff2", + }) + resourceID, _ := out["resource_id"].(string) + if resourceID == "" { + t.Fatalf("manage_resource create returned no resource_id: %v", out) + } + t.Cleanup(func() { _, _ = c.rest(http.MethodDelete, "/api/v1/resources/"+resourceID, http.NoBody) }) + status, row := c.rest(http.MethodGet, "/api/v1/resources/"+resourceID, http.NoBody) + uri, _ = row["uri"].(string) + if status != http.StatusOK || uri == "" { + t.Fatalf("the font resource carries no uri: HTTP %d %v", status, row) + } + saved := c.call("save_asset", map[string]any{ + "name": name, "content": plainPage2234, "content_type": "text/jsx", + "description": "Acceptance #2234: a page that gains a referenced font.", + }) + assetID, _ = saved["asset_id"].(string) + if assetID == "" { + t.Fatalf("save_asset returned no asset_id: %v", saved) + } + t.Cleanup(func() { _, _, _ = c.callRaw("manage_asset", map[string]any{"action": "delete", "asset_id": assetID}) }) + awaitAssetTile1794(t, c, assetID) + return assetID, uri +} + +// TestIssue2234_AnUpdateThatDeclaresAFontIsDrawnWithIt: manage_asset update +// writing the page that declares the font, with the reference, yields a tile +// of the new version drawn in the font. +func TestIssue2234_AnUpdateThatDeclaresAFontIsDrawnWithIt(t *testing.T) { + c := connectFor(t, 3*tileWait1794+time.Minute) + assetID, uri := fontURI2234(t, c) + c.call("manage_asset", map[string]any{ + "action": "update", "asset_id": assetID, "content": fontPage2062(uri), + "references": []any{uri}, "change_summary": "Draw the page in the brand font.", + }) + awaitAssetTile1794(t, c, assetID) + assertDrawnInTheFont2062(t, c, assetID) +} + +// TestIssue2234_APatchThatDeclaresAFontIsDrawnWithIt: manage_asset patch +// replacing the page with the one that declares the font, with the +// reference, yields a tile of the new version drawn in the font. +func TestIssue2234_APatchThatDeclaresAFontIsDrawnWithIt(t *testing.T) { + c := connectFor(t, 3*tileWait1794+time.Minute) + assetID, uri := fontURI2234(t, c) + c.call("manage_asset", map[string]any{ + "action": "patch", "asset_id": assetID, + "edits": []any{map[string]any{"op": "replace", "find": plainPage2234, "replace": fontPage2062(uri)}}, + "references": []any{uri}, "change_summary": "Draw the page in the brand font.", + }) + awaitAssetTile1794(t, c, assetID) + assertDrawnInTheFont2062(t, c, assetID) +} diff --git a/test/acceptance/issue_2236_test.go b/test/acceptance/issue_2236_test.go new file mode 100644 index 000000000..8679b63ee --- /dev/null +++ b/test/acceptance/issue_2236_test.go @@ -0,0 +1,90 @@ +//go:build integration + +package acceptance + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "strings" + "testing" + "time" +) + +// Acceptance for #2236: the api and graphql connection editors set +// oauth_token_lifetime as "Token lifetime". The editor saves through the +// admin connection route, so these criteria save through it as the editor +// does: a value saved is the value read back, an empty field stores nothing, +// and a negative value is refused with the message the editor shows. +// +// Wire forms: oauth_token_lifetime is sent as a duration string ("45m") and +// as a JSON number of seconds (900), the two forms the key admits, and left +// out for an empty field; the rest of the config is strings. + +// issue2236Config is an oauth client_credentials connection of kind to the +// dev stack's Keycloak with the lifetime given; nil leaves the key out. +func issue2236Config(kind, name string, lifetime any) map[string]any { + upstream := map[string]string{"api": "base_url", "graphql": "endpoint_url"}[kind] + cfg := map[string]any{ + upstream: issue1759KeycloakBase(), "connection_name": name, + "auth_mode": "oauth", "oauth_grant": "client_credentials", + "oauth_token_url": issue1759KeycloakBase() + "/realms/mcp-platform/protocol/openid-connect/token", + "oauth_client_id": "acc-2236", "oauth_client_secret": "acc-2236-secret", + } + if lifetime != nil { + cfg["oauth_token_lifetime"] = lifetime + } + return cfg +} + +// issue2236Save saves the connection as the editor does and returns the +// status and the decoded answer. +func issue2236Save(t *testing.T, c *client, kind, name string, cfg map[string]any) (int, map[string]any) { + t.Helper() + raw, err := json.Marshal(map[string]any{"config": cfg, "description": "Acceptance #2236."}) + if err != nil { + t.Fatal(err) + } + return c.rest(http.MethodPut, "/api/v1/admin/connection-instances/"+kind+"/"+name, bytes.NewReader(raw)) +} + +// TestIssue2236_TheTokenLifetimeSavesAndReadsBack: on an api and a graphql +// connection, a lifetime saved as a duration and as seconds reads back as +// saved, an empty field stores nothing, and a negative value is refused +// naming the key. +func TestIssue2236_TheTokenLifetimeSavesAndReadsBack(t *testing.T) { + c := connect(t) + for _, kind := range []string{"api", "graphql"} { + t.Run(kind, func(t *testing.T) { + name := fmt.Sprintf("acc-2236-%s-%d", kind, time.Now().UnixNano()) + t.Cleanup(func() { c.rest(http.MethodDelete, "/api/v1/admin/connection-instances/"+kind+"/"+name, http.NoBody) }) + for _, value := range []any{"45m", float64(900)} { + if status, out := issue2236Save(t, c, kind, name, issue2236Config(kind, name, value)); status != http.StatusOK && status != http.StatusCreated { + t.Fatalf("saving a lifetime of %v answered %d: %v", value, status, out) + } + _, read := c.rest(http.MethodGet, "/api/v1/admin/connection-instances/"+kind+"/"+name, http.NoBody) + cfg, _ := read["config"].(map[string]any) + if fmt.Sprint(cfg["oauth_token_lifetime"]) != fmt.Sprint(value) { + t.Errorf("a lifetime saved as %v (%T) reads back as %v", value, value, cfg["oauth_token_lifetime"]) + } + } + + if status, out := issue2236Save(t, c, kind, name, issue2236Config(kind, name, nil)); status != http.StatusOK && status != http.StatusCreated { + t.Fatalf("saving with the field empty answered %d: %v", status, out) + } + _, read := c.rest(http.MethodGet, "/api/v1/admin/connection-instances/"+kind+"/"+name, http.NoBody) + if cfg, _ := read["config"].(map[string]any); cfg["oauth_token_lifetime"] != nil { + t.Errorf("an empty field stored a lifetime: %v", cfg["oauth_token_lifetime"]) + } + + status, out := issue2236Save(t, c, kind, name, issue2236Config(kind, name, "-5m")) + if status != http.StatusBadRequest { + t.Fatalf("a negative lifetime answered %d: %v", status, out) + } + if detail, _ := out["detail"].(string); !strings.Contains(detail, "oauth_token_lifetime must not be negative") { + t.Errorf("the refusal says %q; want it to name the key", detail) + } + }) + } +} diff --git a/test/acceptance/issue_2237_test.go b/test/acceptance/issue_2237_test.go new file mode 100644 index 000000000..491b6ff2b --- /dev/null +++ b/test/acceptance/issue_2237_test.go @@ -0,0 +1,56 @@ +//go:build integration + +package acceptance + +import ( + "net/http" + "strings" + "testing" +) + +// Acceptance for #2237: a Google API refusing a call a service-account +// connection made carries the operator's next step, chosen by the refusal's +// status and reasons rather than by one product's message text. Google answers +// every API in one error shape, so a 401 UNAUTHENTICATED with any message in +// that shape is read as an account without access in the product. +// +// The connection is #2061's: a Google key file whose grant Keycloak answers, +// with a Google API as its upstream. Google refuses the Keycloak-issued token +// with a 401 UNAUTHENTICATED in its own shape, which carried no hint before +// this change: it is neither PERMISSION_DENIED nor the one product's text the +// hint used to match. +// +// Wire forms: google_service_account_json is sent as a string of JSON, +// oauth_scope as a space-delimited string and base_url as a string; +// api_invoke_endpoint takes method and path strings and no body. + +const googleAPI2237 = "https://sheets.googleapis.com" + +// TestIssue2237_AGoogle401CarriesTheAccessStep: a call through a Google +// service-account connection that Google refuses with 401 UNAUTHENTICATED +// answers with the hint to grant the account access inside the product. +func TestIssue2237_AGoogle401CarriesTheAccessStep(t *testing.T) { + admin := connect(t) + name := "acc-2237-" + unique1579() + if status := connection2061(t, admin, name, grant2061(map[string]any{ + "google_service_account_json": keyFile2061(t), + "base_url": googleAPI2237, + })); status != http.StatusOK && status != http.StatusCreated { + t.Fatalf("saving the connection answered %d", status) + } + out := admin.call("api_invoke_endpoint", map[string]any{ + "connection": name, "method": http.MethodGet, "path": "/v4/spreadsheets/acceptance-2237", + "purpose": "Acceptance #2237: what a Google refusal tells the operator.", + }) + if status, _ := out["status"].(float64); status != http.StatusUnauthorized { + t.Fatalf("Google answered %v, not 401: %v", out["status"], out) + } + body, _ := out["body"].(map[string]any) + refusal, _ := body["error"].(map[string]any) + if refusal["status"] != "UNAUTHENTICATED" { + t.Fatalf("the refusal is not in Google's shape: %v", body) + } + if hint, _ := out["hint"].(string); !strings.Contains(hint, "grant the service account's email access inside the product") { + t.Errorf("the hint is %q; want the access step", hint) + } +} diff --git a/test/structure/testdata/allowed_internal_imports.txt b/test/structure/testdata/allowed_internal_imports.txt index ec4042647..95d042693 100644 --- a/test/structure/testdata/allowed_internal_imports.txt +++ b/test/structure/testdata/allowed_internal_imports.txt @@ -95,6 +95,7 @@ internal/admin/webhookapi -> internal/webhook/whadmin internal/admin/webhookapi -> internal/webhook/whsource internal/admin/webhookapi -> internal/webhook/whstore internal/admin/webhookapi -> internal/webhook/whtable +internal/advisorylock -> internal/logsan internal/agentinstructions -> pkg/configstore internal/apigwmetrics -> pkg/mcpcontext internal/apigwmetrics -> pkg/observability @@ -106,6 +107,7 @@ internal/botcheck -> internal/platform/settingsjson internal/botcheck -> pkg/portal/shareguest internal/catalogfake -> pkg/catalog internal/conncatchup -> internal/logsan +internal/connlimit -> internal/advisorylock internal/connlimit -> pkg/observability internal/connsecretref -> internal/secretref internal/connsecretref -> internal/secretstore @@ -554,6 +556,7 @@ internal/indexpolicy -> pkg/contenttype internal/inlinefit -> pkg/toolkit internal/inproc -> internal/portal/viewerlimit internal/listcut -> internal/pagenext +internal/maps -> internal/advisorylock internal/maps -> internal/bgloop internal/maps -> internal/logsan internal/maps -> internal/pmtiles @@ -627,6 +630,7 @@ internal/platform/callcatchup -> pkg/registry internal/platform/callcatchup -> pkg/toolkit internal/platform/callindex -> internal/platform/callrecord internal/platform/callindex -> pkg/indexjobs +internal/platform/callrecord -> internal/advisorylock internal/platform/callrecord -> internal/bgloop internal/platform/callrecord -> internal/gqlschema internal/platform/callrecord -> internal/httpjson @@ -644,6 +648,7 @@ internal/platform/calltask -> internal/logsan internal/platform/calltask -> internal/mcptask internal/platform/calltask -> pkg/mcpcontext internal/platform/calltask -> pkg/middleware +internal/platform/capacity -> internal/advisorylock internal/platform/capacity -> internal/bgloop internal/platform/capacity -> internal/logsan internal/platform/capacity -> internal/objectobs @@ -651,9 +656,11 @@ internal/platform/capacity -> internal/outbound internal/platform/capacity -> internal/platform/toolkitcfg internal/platform/capacity -> pkg/observability internal/platform/capacity -> pkg/portal/s3adapter +internal/platform/catalogimport -> internal/advisorylock internal/platform/catalogimport -> internal/logsan internal/platform/catalogimport -> internal/outbound internal/platform/catalogimport -> pkg/catalog +internal/platform/catalogscan -> internal/advisorylock internal/platform/catalogscan -> internal/bgloop internal/platform/catalogscan -> internal/logsan internal/platform/catalogscan -> pkg/catalog @@ -772,8 +779,8 @@ internal/platform/knowledgelayer -> pkg/portal/knowledgepage internal/platform/knowledgelayer -> pkg/toolkits/knowledge internal/platform/knowledgepageindex -> pkg/indexjobs internal/platform/knowledgepageindex -> pkg/portal/knowledgepage +internal/platform/levelalert -> internal/advisorylock internal/platform/levelalert -> internal/bgloop -internal/platform/levelalert -> internal/logsan internal/platform/levelalert -> pkg/notification internal/platform/listchanged -> pkg/session internal/platform/listenbridge -> internal/logsan @@ -935,6 +942,7 @@ internal/platform/resourcelayer -> pkg/indexjobs internal/platform/resourcelayer -> pkg/observability internal/platform/resourcelayer -> pkg/portal/s3adapter internal/platform/resourcelayer -> pkg/resource +internal/platform/resourcereclass -> internal/advisorylock internal/platform/resourcereclass -> internal/indexpolicy internal/platform/resourcereclass -> pkg/indexjobs internal/platform/resourcereclass -> pkg/resource @@ -954,6 +962,7 @@ internal/platform/resultbudget -> pkg/mcpcontext internal/platform/resultbudget -> pkg/middleware internal/platform/resultbudget -> pkg/registry internal/platform/resultbudget -> pkg/toolkit +internal/platform/retention -> internal/advisorylock internal/platform/retention -> internal/bgloop internal/platform/retention -> internal/botcheck internal/platform/retention -> internal/endpoint/epbinding @@ -1438,7 +1447,7 @@ internal/shutdown -> internal/inprocess internal/soap -> internal/xmltree internal/tableavail -> pkg/query internal/tableparquet -> internal/tabletype -internal/thumbdue -> internal/logsan +internal/thumbdue -> internal/advisorylock internal/thumbtypes -> pkg/contenttype internal/toolanswer -> pkg/registry internal/toolanswer -> pkg/toolkit @@ -1580,7 +1589,9 @@ pkg/admin -> pkg/toolkits/gateway/enrichment pkg/admin -> pkg/toolkits/knowledge pkg/admin -> pkg/user pkg/audit -> pkg/observability +pkg/audit/postgres -> internal/advisorylock pkg/audit/postgres -> internal/bgloop +pkg/audit/postgres -> internal/logsan pkg/audit/postgres -> pkg/audit pkg/audit/postgres -> pkg/prompt pkg/audit/postgres -> pkg/resource @@ -1602,6 +1613,7 @@ pkg/configstore/postgres -> internal/opsobs pkg/configstore/postgres -> pkg/configstore pkg/connid -> pkg/registry pkg/connid -> pkg/toolkit +pkg/connoauth -> internal/advisorylock pkg/connoauth -> internal/bgloop pkg/connoauth -> internal/logsan pkg/connoauth -> internal/outbound diff --git a/ui/e2e/interactive/connections-oauth.spec.ts b/ui/e2e/interactive/connections-oauth.spec.ts index b8dbc25e3..bb7959262 100644 --- a/ui/e2e/interactive/connections-oauth.spec.ts +++ b/ui/e2e/interactive/connections-oauth.spec.ts @@ -40,6 +40,11 @@ test.describe("Connection editor — a canonical OAuth connection", () => { await expect( page.getByRole("button", { name: "Connect", exact: true }), ).toBeVisible(); + // #2236: how long a token is reused when its endpoint states no expiry. + await expect(page.getByLabel("Token lifetime")).toHaveValue("30m"); + await expect( + page.getByText("Used when the token endpoint states no expiry"), + ).toBeVisible(); }); }); diff --git a/ui/e2e/screenshots/route-connections.ts b/ui/e2e/screenshots/route-connections.ts index bbb35560b..ed0bb19cd 100644 --- a/ui/e2e/screenshots/route-connections.ts +++ b/ui/e2e/screenshots/route-connections.ts @@ -53,6 +53,25 @@ export const adminConnectionRoutes: ScreenshotRoute[] = [ } }, }, + { + // The token lifetime field (#2236) under the OAuth block of an api + // connection whose token endpoint states no expiry. + slug: "admin-connection-token-lifetime", + path: "/portal/admin/connections?kind=api&name=acme-billing-api", + category: "admin", + beforeCapture: async (page) => { + const edit = page.locator("button:has-text('Edit')").first(); + if (await edit.isVisible()) { + await edit.click(); + await page.waitForTimeout(600); + } + const lifetime = page.locator("text=Token lifetime").first(); + if (await lifetime.isVisible()) { + await lifetime.scrollIntoViewIfNeeded(); + await page.waitForTimeout(300); + } + }, + }, { // A connection carrying both OAuth config vocabularies (#1682). The values // nothing reads are struck through and badged rather than listed beside the diff --git a/ui/src/mocks/data/connections.ts b/ui/src/mocks/data/connections.ts index 9295bf415..748dddc03 100644 --- a/ui/src/mocks/data/connections.ts +++ b/ui/src/mocks/data/connections.ts @@ -126,6 +126,8 @@ export const mockConnectionInstances: ConnectionInstance[] = [ oauth_client_secret: "[REDACTED]", oauth_scope: "billing.read", oauth_endpoint_auth_style: "params", + // The billing token endpoint states no expires_in (#2236). + oauth_token_lifetime: "30m", }, description: "HTTP API gateway over the internal billing service. Exposes invoice and subscription lookups as a single `api_invoke` tool with discovery.", diff --git a/ui/src/mocks/handlers.ts b/ui/src/mocks/handlers.ts index 5c9ecf456..358a19f87 100644 --- a/ui/src/mocks/handlers.ts +++ b/ui/src/mocks/handlers.ts @@ -1797,6 +1797,8 @@ export const handlers = [ oauth_client_secret: "[REDACTED]", oauth_scope: "billing.read", oauth_endpoint_auth_style: "params", + // The billing token endpoint states no expires_in (#2236). + oauth_token_lifetime: "30m", }, created_by: "admin@example.com", updated_at: new Date(Date.now() - 4 * 86400000).toISOString(), diff --git a/ui/src/pages/settings/connections/ApiGatewayAuthFields.test.tsx b/ui/src/pages/settings/connections/ApiGatewayAuthFields.test.tsx index fcace7d59..c6fa4b6db 100644 --- a/ui/src/pages/settings/connections/ApiGatewayAuthFields.test.tsx +++ b/ui/src/pages/settings/connections/ApiGatewayAuthFields.test.tsx @@ -209,3 +209,39 @@ describe("ApiGatewayAuthFields — the jwt_bearer grant", () => { ); }); }); + +// #2236: oauth_token_lifetime, how long a token whose endpoint states no +// expiry is reused, is set from the form on api and graphql connections. +describe("ApiGatewayAuthFields — token lifetime", () => { + it("shows the field with its help when the mode is oauth, holding the stored value", () => { + renderFields({ ...canonical, oauth_token_lifetime: "45m" }); + + const field = screen.getByLabelText(/^Token lifetime$/i); + expect(field).toHaveValue("45m"); + expect(screen.getByText("Used when the token endpoint states no expiry")).toBeInTheDocument(); + }); + + it("shows a value stored as seconds", () => { + renderFields({ ...canonical, oauth_token_lifetime: 900 }, "graphql"); + + expect(screen.getByLabelText(/^Token lifetime$/i)).toHaveValue("900"); + }); + + it("writes oauth_token_lifetime", () => { + const onChange = renderFields(canonical); + fireEvent.change(screen.getByLabelText(/^Token lifetime$/i), { target: { value: "30m" } }); + expect(onChange).toHaveBeenLastCalledWith(expect.objectContaining({ oauth_token_lifetime: "30m" })); + }); + + it("stores nothing when emptied, so the server's default applies", () => { + const onChange = renderFields({ ...canonical, oauth_token_lifetime: "30m" }); + fireEvent.change(screen.getByLabelText(/^Token lifetime$/i), { target: { value: "" } }); + expect(onChange.mock.lastCall?.[0]).not.toHaveProperty("oauth_token_lifetime"); + }); + + it("is not shown for a mode that fetches no token", () => { + renderFields({ auth_mode: "bearer", credential: "[REDACTED]" }); + + expect(screen.queryByLabelText(/^Token lifetime$/i)).not.toBeInTheDocument(); + }); +}); diff --git a/ui/src/pages/settings/connections/ApiGatewayAuthFields.tsx b/ui/src/pages/settings/connections/ApiGatewayAuthFields.tsx index bd5c3eede..5ade484ef 100644 --- a/ui/src/pages/settings/connections/ApiGatewayAuthFields.tsx +++ b/ui/src/pages/settings/connections/ApiGatewayAuthFields.tsx @@ -193,6 +193,21 @@ function ConnectPanel({ ); } +// TokenLifetimeField sets oauth_token_lifetime (#2236): how long a token is +// reused when its endpoint's response states no expires_in. Empty stores +// nothing, and the server's 15m default applies. +function TokenLifetimeField({ config, onChange }: ConfigFormProps) { + return ( + onChange(update(config, "oauth_token_lifetime", v))} + placeholder="15m" + /> + ); +} + // ApiGatewayAuthFields renders the mode picker plus whichever credential // block the selected mode needs. The mode set matches what the apigateway // toolkit accepts (pkg/toolkits/apigateway/config.go); mtls carries no fields @@ -259,19 +274,22 @@ export function ApiGatewayAuthFields({ )} {mode === AUTH_MODE_OAUTH && ( - - } - /> + <> + + } + /> + + )}