Repository navigation
fix(app): rediscover a tenant's schema when a reload moves it - #682
Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📜 Recent review details🧰 Additional context used🧠 Learnings (1)📓 Common learnings🔇 Additional comments (1)
📝 SummarySummary by CodeRabbit
WalkthroughWhen a reload changes a tenant’s ClickHouse address or database, the app drops its schema registry and starts discovery against the current pool. Tests cover registry replacement, unchanged tenants, failed discovery, loop shutdown, and ingest-only reloads. A DynamoDB throttling test no longer measures elapsed time. ChangesTenant schema discovery reload
DynamoDB throttling test
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant SettingsReload
participant PoolReconciliation
participant Discovery
participant TenantLookup
SettingsReload->>PoolReconciliation: Reconcile tenant pools
PoolReconciliation->>Discovery: Drop registry for moved tenant
Discovery->>Discovery: Reconcile against current pool
Discovery->>TenantLookup: Provide schema after discovery succeeds
Suggested reviewers: Merge Risk: ⚪ Minimal · up to Reloads refresh schemas when a tenant changes ClickHouse address or database, while username- or TLS-only changes retain normal refresh behavior. No concrete merge-blocking risk remains. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Tenant moves now discard outdated schema information and reject schema-dependent requests until rediscovery succeeds. No new access-control bypass was identified. Requests already in progress can still span a database change, so the change does not establish fully atomic cutover. Retained concerns Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Out of Scope Changes checkExplanation The change in ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
📚 Docs preview is live → https://b5e6aa30-wavehouse-docs.wave-rf.workers.dev |
Code Coverage OverviewLanguages: Go GoThe overall line coverage in commit ec80186 in the Show a line coverage summary of the most impacted files.
Updated |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Advanced
Run ID: 958cb146-bebe-44b0-8e96-18386cda6293
📒 Files selected for processing (11)
AGENTS.mdCHANGELOG.mddocs/src/content/docs/architecture.mddocs/src/content/docs/settings-directory.mdxinternal/app/app_test.gointernal/app/discoveries.gointernal/app/roles_test.gointernal/app/wire.gointernal/dedupe/dynamodb_test.gointernal/discovery/discovery.gointernal/testutil/testutil.go
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
See [AGENTS.md](AGENTS.md) for project conventions, architecture notes, and AI agent instructions.
📄 CodeRabbit inference engine (CLAUDE.md)
Files:
AGENTS.md
See [AGENTS.md](../AGENTS.md) for project conventions, architecture notes, and AI agent instructions.
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
AGENTS.md
Source excerpt: **In MDX, leave a blank line between a JSX tag and a code fence.**
📄 CodeRabbit inference engine (AGENTS.md)
Files:
docs/src/content/docs/settings-directory.mdx
Source excerpt: **WH001 applies to every tracked Markdown file, with no carve-out** — `AGENTS.md`, `CHANGELOG.md`, `.github/` CI docs and `.claude/` agent prompts included.
📄 CodeRabbit inference engine (AGENTS.md)
Files:
AGENTS.mddocs/src/content/docs/architecture.mdCHANGELOG.md
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: Wave-RF/WaveHouse
Timestamp: 2026-09-29T18:14:21.880Z
Learning: Source excerpt:
# AGENTS.md — AI Agent Instructions for WaveHouse
## Testing Conventions
- **Every new function should have corresponding test cases.** Run `make lint` and `make test` before considering work complete.
📚 Learning: 2026-08-13T12:17:52.620Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 470
File: docs/src/content/docs/reverse-proxy.mdx:137-144
Timestamp: 2026-08-13T12:17:52.620Z
Learning: For Wave-RF/WaveHouse documentation, verify claims about implementation control flow against the authoritative implementation source (for example, internal/auth/auth.go) rather than relying solely on docs/** content. Documentation may lag behind or paraphrase behavior, so control-flow claims should be confirmed in source code.
Applied to files:
docs/src/content/docs/settings-directory.mdx
📚 Learning: 2026-06-26T12:23:22.696Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 346
File: internal/stream/subscriber_test.go:9-28
Timestamp: 2026-06-26T12:23:22.696Z
Learning: In this Go repository, prefer table-driven tests (e.g., `[]struct{...}` with `t.Run(...)`) only for tests that cover multiple scenarios/inputs and can be cleanly enumerated. Do not artificially rewrite a clear single-scenario sequential behavioral-flow test into a table-driven form just to fit the pattern; if there’s only one meaningful scenario, keep the test as a straightforward linear flow (as in `TestSubscriber_SendDeliversThenDropsWhenFull`).
Applied to files:
internal/app/roles_test.go
🪛 LanguageTool
docs/src/content/docs/architecture.md
[typographical] ~156-~156: Consider using an em dash in dialogues and enumerations.
Context: - discovery.go — SchemaRegistry, on...
(DASH_RULE)
[style] ~156-~156: This sentence is over 40 words long. Consider splitting it up, as shorter sentences make the text easier to read.
Context: ...ne snapshot (App.discoverySource over chconn.Pools.For in production, so a reload that repoints the tenant to another user or tls block, which reads the same tables, applies to the next refresh, one that moves it to another address or database has internal/app's discoveries drop its registry and build a fresh one, whose first discovery runs at once and whose lookups answer ErrNotLoaded until it succeeds (#638), and a refused move keeps discovering the database the tenant's queries and inserts still use; no pool is ErrNoConnection), queries system.columns to discover ClickHouse table schemas, keeping each column's default_kind so IsInsertable / InsertableColumns / InsertableColumnNames (memoized per table at refresh) can decide the insertable subset the ingest envelope and the SSE announcement are both built from. Each refresh also records the server ve...
(TOO_LONG_SENTENCE)
[style] ~156-~156: This sentence is over 40 words long. Consider splitting it up, as shorter sentences make the text easier to read.
Context: ...e SSE announcement are both built from. Each refresh also records the server version (SELECT version()), joins system.tables for each table's create_table_query (kept in-process as TableSchema.DDL and marked json:"-" — an external-engine table renders its wiring in that statement — endpoint, bucket/host, database, username, access key id — so it must never reach /v1/ops/schema; ClickHouse masks the password as [HIDDEN] from ~23.9, so what is withheld here is the topology), reads each column's default_expression and 1-based position alongside its type, discovers the server's default time zone (SELECT timezone()) and bakes every DateTime/DateTime64 column's canonicalization spec (precision + resolved zone) into the cached schema, so the per-record ingest path parses no type strings and loads no zones (#372). Lookup tells the two misses apart ...
(TOO_LONG_SENTENCE)
CHANGELOG.md
[typographical] ~93-~93: Consider using an em dash in dialogues and enumerations.
Context: - **A tenant moved to another ClickHouse ...
(DASH_RULE)
🔇 Additional comments (9)
internal/dedupe/dynamodb_test.go (1)
557-559: LGTM!internal/discovery/discovery.go (1)
203-204: LGTM!AGENTS.md (1)
40-40: LGTM!CHANGELOG.md (1)
93-93: LGTM!docs/src/content/docs/architecture.md (1)
156-156: LGTM!docs/src/content/docs/settings-directory.mdx (1)
208-208: LGTM!internal/testutil/testutil.go (1)
39-43: LGTM!internal/app/app_test.go (1)
1806-1868: LGTM!Also applies to: 1870-1914, 1916-1934, 1936-1968
internal/app/roles_test.go (1)
159-174: LGTM!
…d wait for stopped loops on close
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Advanced
Run ID: 94e9f27d-faf9-4213-a14b-a13b13f64278
📒 Files selected for processing (3)
internal/app/app_test.gointernal/app/discoveries.gointernal/app/wire.go
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
Source excerpt: Create `*_test.go` files in the same package as the code under test.
📄 CodeRabbit inference engine (AGENTS.md)
Files:
internal/app/app_test.go
Source excerpt: Create the package under `internal/`.
📄 CodeRabbit inference engine (AGENTS.md)
Files:
internal/app/wire.gointernal/app/discoveries.gointernal/app/app_test.go
🔇 Additional comments (3)
internal/app/wire.go (1)
320-329: LGTM!internal/app/discoveries.go (1)
29-30: LGTM!Also applies to: 41-46, 51-51, 88-88, 95-107, 120-120, 141-141, 158-159, 167-167, 169-169, 171-171, 174-174, 176-178, 181-181
internal/app/app_test.go (1)
1970-2008: LGTM!
|
@coderabbitai review |
✅ Action performedReview finished.
|
…-tenant-move # Conflicts: # AGENTS.md # CHANGELOG.md
Summary
A reload that changed a tenant's
clickhouse.addrorclickhouse.databaseorphaned the tenant's cache but left its schema registry as it was. Until the tenant's loop fired atschema.refresh_interval, its queries and inserts were validated against the previous database's schema and run against the new one.A moved tenant now starts over the way a tenant back after a rejection or removal already does:
Pools.Reconcilereports stale, beside the cache invalidation it already ran. The hook runs no network I/O.503withRetry-After: 5, as before any first discovery. They are never answered from the previous database's schema.schema discovery retry failed), counted inwavehouse_schema_refresh_failures_total, and retried with backoff from two seconds to sixty.0moves the same way. A process without the api role, which discovers no schema, only repoints its pool.One behavior change to note: when the new database cannot be reached, the moved tenant's ingest and queries answer
503until it can. Before, they kept validating against the old schema.A second commit removes a wall-clock assertion from
TestDynamo_ThrottledCallEndsOnItsLastAttempt, which failed under load (312ms against a 250ms bound) while the call itself ended correctly. The test still proves the call ended on its last attempt and not on the deadline, from the error.Test plan
TestReload_MovedTenantDiscoversTheNewDatabase: over a nested directory with two tenants, the moved tenant reads the new database's table and not the old one, the other tenant keeps its registry and loop, and a reload that moves nobody touches nobodyTestReload_MovedTenantDiscoversTheNewDatabase_Flat: the same move for tenant0TestReload_MovedTenantFailedDiscoveryIsRetried: the failure is logged with the tenant, ingest answers503for a table the old schema had, and the loop loads once the database answersTestReload_OpsOnlyMovedTenant: an ingest-only process repoints its pool and has no registryclickhouse.addrRelated Issues
Closes #638
Part of #583 (story 6); follow-up named in #610.