Skip to content

Commit b411cfe

Browse files
add: max_bytes_before_external_group_by and max_bytes_before_external_sort and csv logging per byte
1 parent 238b1b8 commit b411cfe

3 files changed

Lines changed: 47 additions & 2 deletions

File tree

apps/worker/src/jobs/import.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,18 @@ export async function importJob(job: Job<ImportQueuePayload>) {
173173
) => providerInstance!.transformEvent(event),
174174
);
175175

176-
await insertImportBatch(transformedEvents, importId);
176+
const result = await insertImportBatch(transformedEvents, importId);
177+
178+
// Log actual CSV data size sent to ClickHouse
179+
const csvSizeMB = result.csvDataSizeBytes
180+
? (result.csvDataSizeBytes / (1024 * 1024)).toFixed(2)
181+
: 'N/A';
182+
183+
jobLogger.info('Inserted batch into ClickHouse', {
184+
batchSize: result.insertedEvents,
185+
csvDataSizeMB: csvSizeMB,
186+
csvDataSizeBytes: result.csvDataSizeBytes || 0,
187+
});
177188

178189
processedEvents += eventBatch.length;
179190
eventBatch = [];
@@ -211,7 +222,18 @@ export async function importJob(job: Job<ImportQueuePayload>) {
211222
) => providerInstance!.transformEvent(event),
212223
);
213224

214-
await insertImportBatch(transformedEvents, importId);
225+
const result = await insertImportBatch(transformedEvents, importId);
226+
227+
// Log actual CSV data size sent to ClickHouse
228+
const csvSizeMB = result.csvDataSizeBytes
229+
? (result.csvDataSizeBytes / (1024 * 1024)).toFixed(2)
230+
: 'N/A';
231+
232+
jobLogger.info('Inserted final batch into ClickHouse', {
233+
batchSize: result.insertedEvents,
234+
csvDataSizeMB: csvSizeMB,
235+
csvDataSizeBytes: result.csvDataSizeBytes || 0,
236+
});
215237

216238
processedEvents += eventBatch.length;
217239
eventBatch = [];

packages/db/src/clickhouse/client.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ export async function chInsertCSV(tableName: string, rows: string[]) {
288288
clickhouse_settings: {
289289
format_csv_allow_double_quotes: 1,
290290
format_csv_allow_single_quotes: 0,
291+
// Memory optimization: prevent OOM by spilling to disk
292+
max_memory_usage: 40000000000, // 40GB max per query
293+
max_bytes_before_external_group_by: 20000000000, // 20GB - spill GROUP BY to disk
294+
max_bytes_before_external_sort: 20000000000, // 20GB - spill ORDER BY to disk
291295
},
292296
});
293297
}

packages/db/src/services/import.service.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface ImportStageResult {
1616
importId: string;
1717
totalEvents: number;
1818
insertedEvents: number;
19+
csvDataSizeBytes?: number;
1920
}
2021

2122
export interface ImportProgress {
@@ -78,6 +79,9 @@ export async function insertImportBatch(
7879
return fields.join(',');
7980
});
8081

82+
// Calculate actual CSV data size being sent to ClickHouse
83+
const csvDataSize = csvRows.reduce((sum, row) => sum + row.length + 1, 0);
84+
8185
await chInsertCSV(TABLE_NAMES.events_imports, csvRows);
8286

8387
// Explicitly release memory
@@ -87,6 +91,7 @@ export async function insertImportBatch(
8791
importId,
8892
totalEvents: events.length,
8993
insertedEvents: events.length,
94+
csvDataSizeBytes: csvDataSize,
9095
};
9196
}
9297

@@ -209,6 +214,12 @@ export async function createSessionsStartEndEvents(
209214
query: sessionEventsQuery,
210215
query_params: { importId, from },
211216
format: 'JSONEachRow',
217+
clickhouse_settings: {
218+
// Memory optimization: prevent OOM on large GROUP BY operations
219+
max_memory_usage: 40000000000, // 40GB max per query
220+
max_bytes_before_external_group_by: 20000000000, // 20GB - spill GROUP BY to disk
221+
max_bytes_before_external_sort: 20000000000, // 20GB - spill ORDER BY to disk
222+
},
212223
});
213224

214225
const sessionData = (await sessionEventsResult.json()) as Array<{
@@ -508,6 +519,10 @@ export async function moveImportsToProduction(
508519
send_progress_in_http_headers: 1,
509520
// The interval of sending these progress headers. Here it is less than 60s,
510521
http_headers_progress_interval_ms: '50000',
522+
// Memory optimization: prevent OOM by spilling to disk
523+
max_memory_usage: 40000000000, // 40GB max per query
524+
max_bytes_before_external_group_by: 20000000000, // 20GB - spill GROUP BY to disk
525+
max_bytes_before_external_sort: 20000000000, // 20GB - spill ORDER BY to disk
511526
},
512527
});
513528
console.log('[Phase 4] Migration completed successfully');
@@ -633,6 +648,10 @@ export async function backfillSessionsToProduction(
633648
send_progress_in_http_headers: 1,
634649
// The interval of sending these progress headers. Here it is less than 60s,
635650
http_headers_progress_interval_ms: '50000',
651+
// Memory optimization: prevent OOM by spilling to disk
652+
max_memory_usage: 40000000000, // 40GB max per query
653+
max_bytes_before_external_group_by: 20000000000, // 20GB - spill GROUP BY to disk
654+
max_bytes_before_external_sort: 20000000000, // 20GB - spill ORDER BY to disk
636655
},
637656
});
638657
console.log('[Phase 5] Sessions backfill completed successfully');

0 commit comments

Comments
 (0)