Skip to content

Commit 2d39fe4

Browse files
authored
fix: Do not fail if partitions are not ready for specified date range interval but there's at least one ready for pre-aggregation (#6026)
1 parent 7ec839e commit 2d39fe4

File tree

2 files changed

+55
-32
lines changed

2 files changed

+55
-32
lines changed

packages/cubejs-query-orchestrator/src/orchestrator/PreAggregations.ts

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,33 +1595,47 @@ export class PreAggregationPartitionRangeLoader {
15951595

15961596
public async loadPreAggregations(): Promise<LoadPreAggregationResult> {
15971597
if (this.preAggregation.partitionGranularity && !this.preAggregation.expandedPartition) {
1598-
const { buildRange, partitionRanges } = await this.partitionRanges();
1599-
const partitionLoaders = partitionRanges.map(range => new PreAggregationLoader(
1600-
this.redisPrefix,
1601-
this.driverFactory,
1602-
this.logger,
1603-
this.queryCache,
1604-
this.preAggregations,
1605-
this.partitionPreAggregationDescription(range, buildRange),
1606-
this.preAggregationsTablesToTempTables,
1607-
this.loadCache,
1608-
this.options,
1609-
));
1610-
const resolveResults = await Promise.all(partitionLoaders.map(async (l, i) => {
1611-
const result = await l.loadPreAggregation(false);
1612-
return result && {
1613-
...result,
1614-
partitionRange: partitionRanges[i]
1615-
};
1616-
}));
1617-
let loadResults = resolveResults.filter(res => res !== null);
1618-
if (this.options.externalRefresh && loadResults.length === 0) {
1598+
const loadPreAggregationsByPartitionRanges = async ({ buildRange, partitionRanges }: PartitionRanges) => {
1599+
const partitionLoaders = partitionRanges.map(range => new PreAggregationLoader(
1600+
this.redisPrefix,
1601+
this.driverFactory,
1602+
this.logger,
1603+
this.queryCache,
1604+
this.preAggregations,
1605+
this.partitionPreAggregationDescription(range, buildRange),
1606+
this.preAggregationsTablesToTempTables,
1607+
this.loadCache,
1608+
this.options,
1609+
));
1610+
const resolveResults = await Promise.all(partitionLoaders.map(async (l, i) => {
1611+
const result = await l.loadPreAggregation(false);
1612+
return result && {
1613+
...result,
1614+
partitionRange: partitionRanges[i]
1615+
};
1616+
}));
1617+
return { loadResults: resolveResults.filter(res => res !== null), partitionLoaders };
1618+
};
1619+
1620+
// eslint-disable-next-line prefer-const
1621+
let loadResultAndLoaders = await loadPreAggregationsByPartitionRanges(await this.partitionRanges());
1622+
if (this.options.externalRefresh && loadResultAndLoaders.loadResults.length === 0) {
1623+
loadResultAndLoaders = await loadPreAggregationsByPartitionRanges(await this.partitionRanges(true));
1624+
// In case there're no partitions ready at matched time dimension intersection then no data can be retrieved.
1625+
// We need to provide any table so query can just execute successfully.
1626+
if (loadResultAndLoaders.loadResults.length > 0) {
1627+
loadResultAndLoaders.loadResults = [loadResultAndLoaders.loadResults[loadResultAndLoaders.loadResults.length - 1]];
1628+
}
1629+
}
1630+
if (this.options.externalRefresh && loadResultAndLoaders.loadResults.length === 0) {
16191631
throw new Error(
16201632
// eslint-disable-next-line no-use-before-define
1621-
PreAggregations.noPreAggregationPartitionsBuiltMessage(partitionLoaders.map(p => p.preAggregation))
1633+
PreAggregations.noPreAggregationPartitionsBuiltMessage(loadResultAndLoaders.partitionLoaders.map(p => p.preAggregation))
16221634
);
16231635
}
16241636

1637+
let { loadResults } = loadResultAndLoaders;
1638+
16251639
let lambdaTable: InlineTable;
16261640
let emptyResult = false;
16271641

@@ -1727,14 +1741,14 @@ export class PreAggregationPartitionRangeLoader {
17271741
}
17281742
}
17291743

1730-
private async partitionRanges(): Promise<PartitionRanges> {
1744+
private async partitionRanges(ignoreMatchedDateRange?: boolean): Promise<PartitionRanges> {
17311745
const buildRange = await this.loadBuildRange();
17321746
if (!buildRange[0] || !buildRange[1]) {
17331747
return { buildRange, partitionRanges: [] };
17341748
}
17351749
let dateRange = PreAggregationPartitionRangeLoader.intersectDateRanges(
17361750
buildRange,
1737-
this.preAggregation.matchedTimeDimensionDateRange,
1751+
ignoreMatchedDateRange ? undefined : this.preAggregation.matchedTimeDimensionDateRange,
17381752
);
17391753
if (!dateRange) {
17401754
// If there's no date range intersection between query data range and pre-aggregation build range

packages/cubejs-query-orchestrator/test/unit/QueryOrchestrator.test.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,8 +1076,8 @@ describe('QueryOrchestrator', () => {
10761076
});
10771077

10781078
test('empty partitions with externalRefresh', async () => {
1079-
const query = {
1080-
query: 'SELECT * FROM stb_pre_aggregations.orders_d',
1079+
const query = ({ startQuery, endQuery, matchedTimeDimensionDateRange }) => ({
1080+
query: 'SELECT * FROM stb_pre_aggregations.orders_empty',
10811081
values: [],
10821082
cacheKeyQueries: {
10831083
queries: []
@@ -1100,19 +1100,28 @@ describe('QueryOrchestrator', () => {
11001100
indexName: 'orders_d_main'
11011101
}],
11021102
preAggregationStartEndQueries: [
1103-
['SELECT MIN(created_at) FROM orders', []],
1104-
['SELECT MAX(created_at) FROM orders', []],
1103+
[startQuery || 'SELECT MIN(created_at) FROM orders', []],
1104+
[endQuery || 'SELECT MAX(created_at) FROM orders', []],
11051105
],
11061106
partitionGranularity: 'day',
1107-
timezone: 'UTC'
1107+
timezone: 'UTC',
1108+
matchedTimeDimensionDateRange
11081109
}],
1109-
requestId: 'empty partitions',
1110-
};
1110+
requestId: 'empty partitions with externalRefresh',
1111+
});
11111112
await expect(async () => {
1112-
await queryOrchestratorExternalRefresh.fetchQuery(query);
1113+
await queryOrchestratorExternalRefresh.fetchQuery(query({}));
11131114
}).rejects.toThrow(
11141115
/refresh worker/
11151116
);
1117+
await queryOrchestrator.fetchQuery(query({ startQuery: 'SELECT \'2021-05-01\'', endQuery: 'SELECT \'2021-05-15\'' }));
1118+
const result = await queryOrchestratorExternalRefresh.fetchQuery(query({
1119+
startQuery: 'SELECT \'2021-05-01\'',
1120+
endQuery: 'SELECT \'2021-05-15\'',
1121+
matchedTimeDimensionDateRange: ['2021-05-31T00:00:00.000', '2021-05-31T23:59:59.999']
1122+
}));
1123+
console.log(JSON.stringify(result, null, 2));
1124+
expect(result.data[0]).toMatch(/orders_empty20210515/);
11161125
});
11171126

11181127
test('empty intersection', async () => {

0 commit comments

Comments
 (0)