@@ -20,6 +20,10 @@ export interface IngestQueueMessage {
2020 ingestedAt : number ;
2121}
2222
23+ function elapsedMs ( startedAt : number ) : number {
24+ return Date . now ( ) - startedAt ;
25+ }
26+
2327/**
2428 * Creates a streaming item extractor that uses a low-level Tokenizer to parse
2529 * items from `$.data[]` one at a time, with a per-item byte budget.
@@ -194,6 +198,7 @@ async function processMessage(
194198 while ( pending . length > 0 ) {
195199 const rawItem = pending . shift ( ) ;
196200 if ( ! rawItem ) break ;
201+ const itemStartedAt = Date . now ( ) ;
197202 try {
198203 await processItem (
199204 env ,
@@ -209,6 +214,7 @@ async function processMessage(
209214 console . error ( 'Error processing single item in queue consumer, continuing' , {
210215 r2Key,
211216 type : rawItem [ 'type' ] ,
217+ durationMs : elapsedMs ( itemStartedAt ) ,
212218 error : err instanceof Error ? err . message : String ( err ) ,
213219 } ) ;
214220 }
@@ -253,25 +259,45 @@ async function processItem(
253259
254260 const item = parsed . data ;
255261 const { item_id } = getItemIdentity ( item ) ;
262+ const startedAt = Date . now ( ) ;
256263
257264 // Check if item data exceeds DO SQLite row limit (use byte length for non-ASCII safety)
258265 const itemDataJson = JSON . stringify ( item . data ) ;
266+ const itemDataBytes = new TextEncoder ( ) . encode ( itemDataJson ) . byteLength ;
259267 let r2References : Record < string , string > | undefined ;
260- if ( new TextEncoder ( ) . encode ( itemDataJson ) . byteLength > MAX_INGEST_ITEM_BYTES ) {
268+ let r2PutMs = 0 ;
269+ if ( itemDataBytes > MAX_INGEST_ITEM_BYTES ) {
261270 const itemR2Key = `items/${ kiloUserId } /${ sessionId } /${ item_id } /${ ingestedAt } ` ;
271+ const r2PutStartedAt = Date . now ( ) ;
262272 await env . SESSION_INGEST_R2 . put ( itemR2Key , itemDataJson ) ;
273+ r2PutMs = elapsedMs ( r2PutStartedAt ) ;
263274 r2References = { [ item_id ] : itemR2Key } ;
264275 }
265276
277+ const doIngestStartedAt = Date . now ( ) ;
266278 const ingestResult = await withDORetry (
267279 ( ) => getSessionIngestDO ( env , { kiloUserId, sessionId } ) ,
268280 stub => stub . ingest ( [ item ] , kiloUserId , sessionId , ingestVersion , ingestedAt , r2References ) ,
269281 'SessionIngestDO.ingest'
270282 ) ;
283+ const doIngestMs = elapsedMs ( doIngestStartedAt ) ;
271284
272285 for ( const change of ingestResult . changes ) {
273286 mergedChanges . set ( change . name , change . value ) ;
274287 }
288+
289+ const durationMs = elapsedMs ( startedAt ) ;
290+ console . info ( 'session-ingest processItem timing' , {
291+ r2Key,
292+ sessionId,
293+ type : item . type ,
294+ itemDataBytes,
295+ r2Referenced : r2References !== undefined ,
296+ r2PutMs,
297+ doIngestMs,
298+ durationMs,
299+ changes : ingestResult . changes . length ,
300+ } ) ;
275301}
276302
277303type SessionMetadataUpdates = Partial <
@@ -349,6 +375,7 @@ async function applyMetadataChanges(
349375 mergedChanges . has ( 'gitBranch' ) ||
350376 parentSessionId !== undefined ;
351377
378+ const transactionStartedAt = Date . now ( ) ;
352379 const notification = await db . transaction ( async tx => {
353380 const statusChange =
354381 status === undefined
@@ -454,6 +481,12 @@ async function applyMetadataChanges(
454481 session : mapSessionEventRow ( persistedRow ) ,
455482 } ;
456483 } ) ;
484+ const transactionMs = elapsedMs ( transactionStartedAt ) ;
485+ console . info ( 'session-ingest applyMetadataChanges transaction timing' , {
486+ sessionId,
487+ metadataChanges : mergedChanges . size ,
488+ transactionMs,
489+ } ) ;
457490
458491 if ( ! notification ) return ;
459492
0 commit comments