Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,10 @@ export class PreAggregations {
tables = tables.filter(row => `${schema}.${row.table_name}` === table);

// fetching query result
const conn = await this.queue[dataSource].getQueueDriver().createConnection();
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);
Comment on lines +471 to +474

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Suggested change
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);
}


// calculating status
let status: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,38 @@ describe('PreAggregations', () => {
});
});

describe('isPartitionExist', () => {
test('initializes a missing data source queue before checking the job result', async () => {
const preAggregations = new PreAggregations(
'TEST',
mockDriverFactory as any,
// eslint-disable-next-line @typescript-eslint/no-empty-function
() => {},
queryCache!,
{
cacheAndQueueDriver: 'memory',
queueOptions: async () => ({
executionTimeout: 1,
concurrency: 2,
}),
},
);
mockDriver!.tables.push('stb_pre_aggregations.orders_main');

await expect(
preAggregations.isPartitionExist(
'request-id',
false,
'named_data_source',
'stb_pre_aggregations',
'stb_pre_aggregations.orders_main',
['job-key'],
'job-token',
)
).resolves.toEqual([true, 'done']);
});
Comment on lines +311 to +312

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 the result == null branch.

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.

});

describe('loadAllPreAggregationsIfNeeded', () => {
let preAggregations: PreAggregations | null = null;

Expand Down
Loading