Skip to content

Commit 1bb6cfd

Browse files
add: logging for duplicate events
1 parent fe7b2be commit 1bb6cfd

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

apps/worker/src/jobs/import.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ export async function importJob(job: Job<ImportQueuePayload>) {
139139

140140
// Phase 1: Fetch & Transform - Process events in batches
141141
if (shouldRunStep('loading')) {
142+
// Track insert_ids to detect duplicates from Mixpanel
143+
const seenInsertIds: Record<string, number> = {};
144+
let totalDuplicatesDetected = 0;
145+
142146
let eventBatch: any = [];
143147
for await (const rawEvent of providerInstance.parseSource(
144148
resumeLoadingFrom,
@@ -158,9 +162,26 @@ export async function importJob(job: Job<ImportQueuePayload>) {
158162

159163
// Process batch when it reaches the batch size
160164
if (eventBatch.length >= BATCH_SIZE) {
165+
// Check for duplicate insert_ids in this batch
166+
let batchDuplicates = 0;
167+
for (const rawEvent of eventBatch) {
168+
const insertId = rawEvent.properties?.$insert_id;
169+
if (insertId) {
170+
const count = seenInsertIds[insertId] || 0;
171+
if (count > 0) {
172+
batchDuplicates++;
173+
totalDuplicatesDetected++;
174+
console.log(`🔄 Duplicate insert_id detected from Mixpanel: ${insertId} (occurrence: ${count + 1}, event: ${rawEvent.event})`);
175+
}
176+
seenInsertIds[insertId] = count + 1;
177+
}
178+
}
179+
161180
const memUsage = process.memoryUsage();
162181
jobLogger.info('Processing batch', {
163182
batchSize: eventBatch.length,
183+
duplicatesInBatch: batchDuplicates,
184+
totalDuplicates: totalDuplicatesDetected,
164185
heapUsedMB: Math.round(memUsage.heapUsed / 1024 / 1024),
165186
heapTotalMB: Math.round(memUsage.heapTotal / 1024 / 1024),
166187
externalMB: Math.round(memUsage.external / 1024 / 1024),
@@ -196,9 +217,26 @@ export async function importJob(job: Job<ImportQueuePayload>) {
196217

197218
// Process remaining events in the last batch
198219
if (eventBatch.length > 0) {
220+
// Check for duplicate insert_ids in final batch
221+
let batchDuplicates = 0;
222+
for (const rawEvent of eventBatch) {
223+
const insertId = rawEvent.properties?.$insert_id;
224+
if (insertId) {
225+
const count = seenInsertIds[insertId] || 0;
226+
if (count > 0) {
227+
batchDuplicates++;
228+
totalDuplicatesDetected++;
229+
console.log(`🔄 Duplicate insert_id detected from Mixpanel: ${insertId} (occurrence: ${count + 1}, event: ${rawEvent.event})`);
230+
}
231+
seenInsertIds[insertId] = count + 1;
232+
}
233+
}
234+
199235
const memUsage = process.memoryUsage();
200236
jobLogger.info('Processing final batch', {
201237
batchSize: eventBatch.length,
238+
duplicatesInBatch: batchDuplicates,
239+
totalDuplicates: totalDuplicatesDetected,
202240
heapUsedMB: Math.round(memUsage.heapUsed / 1024 / 1024),
203241
heapTotalMB: Math.round(memUsage.heapTotal / 1024 / 1024),
204242
externalMB: Math.round(memUsage.external / 1024 / 1024),
@@ -230,6 +268,20 @@ export async function importJob(job: Job<ImportQueuePayload>) {
230268
// Yield control back to event loop after processing final batch
231269
await yieldToEventLoop();
232270
}
271+
272+
// Log summary of duplicate detection
273+
const uniqueInsertIds = Object.keys(seenInsertIds).length;
274+
console.log('\n📊 Phase 1 Import Summary:');
275+
console.log(` Total events processed: ${processedEvents}`);
276+
console.log(` Unique insert_ids: ${uniqueInsertIds}`);
277+
console.log(` Duplicates detected: ${totalDuplicatesDetected}`);
278+
if (totalDuplicatesDetected > 0) {
279+
const duplicatePercentage = ((totalDuplicatesDetected / processedEvents) * 100).toFixed(2);
280+
console.log(` Duplication rate: ${duplicatePercentage}%`);
281+
console.log(`\n⚠️ Mixpanel sent ${totalDuplicatesDetected} duplicate events (same $insert_id multiple times)`);
282+
} else {
283+
console.log(`\n✅ No duplicates detected from Mixpanel`);
284+
}
233285
}
234286

235287
// Phase 2: Generate session IDs if provider requires it

0 commit comments

Comments
 (0)