fix(query-orchestrator): initialize missing data source queue in isPa… - #11617
Conversation
90208f4 to
b138d98
Compare
…rtitionExist Polling job status from a replica that never built that data source crashed on this.queue[dataSource].getQueueDriver(). Create the queue via getQueue() first, matching the other queue accessors. Co-authored-by: Cursor <cursoragent@cursor.com>
b138d98 to
de539cf
Compare
|
/bot-review |
|
Claude finished @ovr's task in 1m 24s —— View job Review: looks correct — 0 blocking, 2 low (1 connection-leak nit, 1 test suggestion)Full review
VerdictThe fix is correct and minimal. No security or auth surface here — Findings
Notes / non-issues
VerificationI could not execute |
| const queue = await this.getQueue(dataSource); | ||
| const conn = await queue.getQueueDriver().createConnection(); | ||
| const result = await conn.getResult(key); | ||
| this.queue[dataSource].getQueueDriver().release(conn); | ||
| queue.getQueueDriver().release(conn); |
There was a problem hiding this comment.
Since these lines are being rewritten anyway, worth closing the pre-existing connection leak: if conn.getResult(key) rejects (Cube Store hiccup, timeout), release(conn) never runs and the queue-driver connection is leaked. For the CubeStore queue driver that's a pooled connection held for the process lifetime, and this is a polling endpoint, so leaks accumulate per failed poll.
| const queue = await this.getQueue(dataSource); | |
| const conn = await queue.getQueueDriver().createConnection(); | |
| const result = await conn.getResult(key); | |
| this.queue[dataSource].getQueueDriver().release(conn); | |
| queue.getQueueDriver().release(conn); | |
| const queue = await this.getQueue(dataSource); | |
| const conn = await queue.getQueueDriver().createConnection(); | |
| let result; | |
| try { | |
| result = await conn.getResult(key); | |
| } finally { | |
| queue.getQueueDriver().release(conn); | |
| } |
| ).resolves.toEqual([true, 'done']); | ||
| }); |
There was a problem hiding this comment.
The test covers the crash path (before the fix this threw Cannot read properties of undefined), which is the important part. Two small strengtheners, both optional:
- Assert the side effect explicitly, e.g.
expect(Object.keys(preAggregations.getQueues())).toContain('named_data_source')— it documents why the call no longer throws rather than relying on the absence of a TypeError. - Add a companion case where the table is absent, asserting
[true, 'missing_partition']for the unknown data source; that's the more common replica-poll shape (job still building) and exercises theresult == nullbranch.
Also, nothing shuts the created queue down at the end of the test. With cacheAndQueueDriver: 'memory' that should be inert (no reconcile is triggered), but if jest ever reports open handles on this file, this is the first place to look.
|
Thank you, @dochernyshov, for your contribution! 🍰 👍 |
|
@dochernyshov, I plan to do an additional fix for this place. I will close #11615 later. Thanks |
…rtitionExist
Polling job status from a replica that never built that data source crashed on this.queue[dataSource].getQueueDriver(). Create the queue via getQueue() first, matching the other queue accessors.
Check List
Issue Reference this PR resolves
Related to #11313 (queue lookup used only default). That did not cover this crash.
Created a new one #11615
Description of Changes Made (if issue reference is not provided)
POST /cubejs-api/v1/pre-aggregations/jobs{ "action": "get" }callsisPartitionExist, which didthis.queue[dataSource].getQueueDriver(). this.queueis per process. On a replica that never built that data source the key is missing, so the poll 500s with Cannot read properties of undefined (reading 'getQueueDriver') even when Cube Store already has the result.