@@ -1162,6 +1162,9 @@ export default function TraceManagerDebugger<
1162
1162
} , [ float , isDragging , dragOffset ] )
1163
1163
1164
1164
useEffect ( ( ) => {
1165
+ // schedule updates asynchronously so we never call setState mid‐render
1166
+ const schedule = ( fn : ( ) => void ) => void setTimeout ( fn , 0 )
1167
+
1165
1168
// Subscribe to trace-start events
1166
1169
const startSub = traceManager . when ( 'trace-start' ) . subscribe ( ( event ) => {
1167
1170
const trace = event . traceContext as AllPossibleTraces < RelationSchemasT >
@@ -1208,7 +1211,7 @@ export default function TraceManagerDebugger<
1208
1211
) ,
1209
1212
}
1210
1213
1211
- setCurrentTrace ( traceInfo )
1214
+ schedule ( ( ) => void setCurrentTrace ( traceInfo ) )
1212
1215
} )
1213
1216
1214
1217
// Subscribe to state transition events
@@ -1218,62 +1221,65 @@ export default function TraceManagerDebugger<
1218
1221
const trace = event . traceContext as AllPossibleTraces < RelationSchemasT >
1219
1222
const transition = event . stateTransition
1220
1223
1221
- setCurrentTrace ( ( prevTrace ) => {
1222
- if ( ! prevTrace || prevTrace . traceId !== trace . input . id )
1223
- return prevTrace
1224
-
1225
- const updatedTrace : TraceInfo < RelationSchemasT > = {
1226
- ...prevTrace ,
1227
- state : transition . transitionToState ,
1228
- attributes : trace . input . attributes
1229
- ? { ...trace . input . attributes }
1230
- : undefined ,
1231
- relatedTo : trace . input . relatedTo
1232
- ? { ...trace . input . relatedTo }
1233
- : undefined ,
1234
- }
1224
+ schedule (
1225
+ ( ) =>
1226
+ void setCurrentTrace ( ( prevTrace ) => {
1227
+ if ( ! prevTrace || prevTrace . traceId !== trace . input . id )
1228
+ return prevTrace
1229
+
1230
+ const updatedTrace : TraceInfo < RelationSchemasT > = {
1231
+ ...prevTrace ,
1232
+ state : transition . transitionToState ,
1233
+ attributes : trace . input . attributes
1234
+ ? { ...trace . input . attributes }
1235
+ : undefined ,
1236
+ relatedTo : trace . input . relatedTo
1237
+ ? { ...trace . input . relatedTo }
1238
+ : undefined ,
1239
+ }
1235
1240
1236
- if ( 'interruptionReason' in transition ) {
1237
- updatedTrace . interruptionReason = transition . interruptionReason
1238
- }
1241
+ if ( 'interruptionReason' in transition ) {
1242
+ updatedTrace . interruptionReason = transition . interruptionReason
1243
+ }
1239
1244
1240
- if (
1241
- 'lastRequiredSpanAndAnnotation' in transition &&
1242
- transition . lastRequiredSpanAndAnnotation
1243
- ) {
1244
- updatedTrace . lastRequiredSpanOffset =
1245
- transition . lastRequiredSpanAndAnnotation . annotation . operationRelativeEndTime
1246
- }
1245
+ if (
1246
+ 'lastRequiredSpanAndAnnotation' in transition &&
1247
+ transition . lastRequiredSpanAndAnnotation
1248
+ ) {
1249
+ updatedTrace . lastRequiredSpanOffset =
1250
+ transition . lastRequiredSpanAndAnnotation . annotation . operationRelativeEndTime
1251
+ }
1247
1252
1248
- if (
1249
- 'completeSpanAndAnnotation' in transition &&
1250
- transition . completeSpanAndAnnotation
1251
- ) {
1252
- updatedTrace . completeSpanOffset =
1253
- transition . completeSpanAndAnnotation . annotation . operationRelativeEndTime
1254
- }
1253
+ if (
1254
+ 'completeSpanAndAnnotation' in transition &&
1255
+ transition . completeSpanAndAnnotation
1256
+ ) {
1257
+ updatedTrace . completeSpanOffset =
1258
+ transition . completeSpanAndAnnotation . annotation . operationRelativeEndTime
1259
+ }
1255
1260
1256
- if (
1257
- 'cpuIdleSpanAndAnnotation' in transition &&
1258
- transition . cpuIdleSpanAndAnnotation
1259
- ) {
1260
- updatedTrace . cpuIdleSpanOffset =
1261
- transition . cpuIdleSpanAndAnnotation . annotation . operationRelativeEndTime
1262
- }
1261
+ if (
1262
+ 'cpuIdleSpanAndAnnotation' in transition &&
1263
+ transition . cpuIdleSpanAndAnnotation
1264
+ ) {
1265
+ updatedTrace . cpuIdleSpanOffset =
1266
+ transition . cpuIdleSpanAndAnnotation . annotation . operationRelativeEndTime
1267
+ }
1263
1268
1264
- // Terminal states - add to history
1265
- if ( isTerminalState ( transition . transitionToState ) ) {
1266
- setTraceHistory ( ( prev ) => {
1267
- updatedTrace . finalTransition =
1268
- transition as FinalTransition < RelationSchemasT >
1269
- const newHistory = [ updatedTrace , ...prev ]
1270
- return newHistory . slice ( 0 , traceHistoryLimit )
1271
- } )
1272
- return null
1273
- }
1269
+ // Terminal states - add to history
1270
+ if ( isTerminalState ( transition . transitionToState ) ) {
1271
+ setTraceHistory ( ( prev ) => {
1272
+ updatedTrace . finalTransition =
1273
+ transition as FinalTransition < RelationSchemasT >
1274
+ const newHistory = [ updatedTrace , ...prev ]
1275
+ return newHistory . slice ( 0 , traceHistoryLimit )
1276
+ } )
1277
+ return null
1278
+ }
1274
1279
1275
- return updatedTrace
1276
- } )
1280
+ return updatedTrace
1281
+ } ) ,
1282
+ )
1277
1283
} )
1278
1284
1279
1285
// Subscribe to required span seen events
@@ -1282,28 +1288,31 @@ export default function TraceManagerDebugger<
1282
1288
. subscribe ( ( event ) => {
1283
1289
const trace = event . traceContext as AllPossibleTraces < RelationSchemasT >
1284
1290
1285
- setCurrentTrace ( ( prevTrace ) => {
1286
- if ( ! prevTrace || prevTrace . traceId !== trace . input . id ) {
1287
- return prevTrace
1288
- }
1289
- // Find which required span was matched by comparing against all matchers
1290
- const updatedRequiredSpans = [ ...prevTrace . requiredSpans ]
1291
- const matchedSpan = event . spanAndAnnotation
1292
-
1293
- trace . definition . requiredSpans . forEach ( ( matcher , index ) => {
1294
- if ( matcher ( matchedSpan , trace ) ) {
1295
- updatedRequiredSpans [ index ] = {
1296
- ...updatedRequiredSpans [ index ] ! ,
1297
- isMatched : true ,
1291
+ schedule (
1292
+ ( ) =>
1293
+ void setCurrentTrace ( ( prevTrace ) => {
1294
+ if ( ! prevTrace || prevTrace . traceId !== trace . input . id ) {
1295
+ return prevTrace
1298
1296
}
1299
- }
1300
- } )
1301
-
1302
- return {
1303
- ...prevTrace ,
1304
- requiredSpans : updatedRequiredSpans ,
1305
- }
1306
- } )
1297
+ // Find which required span was matched by comparing against all matchers
1298
+ const updatedRequiredSpans = [ ...prevTrace . requiredSpans ]
1299
+ const matchedSpan = event . spanAndAnnotation
1300
+
1301
+ trace . definition . requiredSpans . forEach ( ( matcher , index ) => {
1302
+ if ( matcher ( matchedSpan , trace ) ) {
1303
+ updatedRequiredSpans [ index ] = {
1304
+ ...updatedRequiredSpans [ index ] ! ,
1305
+ isMatched : true ,
1306
+ }
1307
+ }
1308
+ } )
1309
+
1310
+ return {
1311
+ ...prevTrace ,
1312
+ requiredSpans : updatedRequiredSpans ,
1313
+ }
1314
+ } ) ,
1315
+ )
1307
1316
} )
1308
1317
1309
1318
const entries : SpanAndAnnotation < RelationSchemasT > [ ] = [ ]
@@ -1312,58 +1321,65 @@ export default function TraceManagerDebugger<
1312
1321
const addSpanSub = traceManager
1313
1322
. when ( 'add-span-to-recording' )
1314
1323
. subscribe ( ( event ) => {
1315
- setCurrentTrace ( ( prevTrace ) => {
1316
- if ( ! prevTrace ) return prevTrace
1317
- if ( event . traceContext . input . id !== prevTrace . traceId ) {
1318
- return prevTrace
1319
- }
1320
- // Calculate live info from traceContext
1321
- const trace = event . traceContext
1322
- entries . push ( event . spanAndAnnotation )
1323
-
1324
- const liveDuration =
1325
- entries . length > 0
1326
- ? Math . round (
1327
- Math . max (
1328
- ...entries . map (
1329
- ( e ) => e . span . startTime . epoch + e . span . duration ,
1330
- ) ,
1331
- ) - trace . input . startTime . epoch ,
1332
- )
1333
- : 0
1334
- const totalSpanCount = entries . length
1335
- const hasErrorSpan = entries . some (
1336
- ( e ) => e . span . status === 'error' && ! isSuppressedError ( trace , e ) ,
1337
- )
1338
- const hasSuppressedErrorSpan = entries . some (
1339
- ( e ) => e . span . status === 'error' && isSuppressedError ( trace , e ) ,
1340
- )
1341
- return {
1342
- ...prevTrace ,
1343
- liveDuration,
1344
- totalSpanCount,
1345
- hasErrorSpan,
1346
- hasSuppressedErrorSpan,
1347
- }
1348
- } )
1324
+ schedule (
1325
+ ( ) =>
1326
+ void setCurrentTrace ( ( prevTrace ) => {
1327
+ if ( ! prevTrace ) return prevTrace
1328
+ if ( event . traceContext . input . id !== prevTrace . traceId ) {
1329
+ return prevTrace
1330
+ }
1331
+ // Calculate live info from traceContext
1332
+ const trace = event . traceContext
1333
+ entries . push ( event . spanAndAnnotation )
1334
+
1335
+ const liveDuration =
1336
+ entries . length > 0
1337
+ ? Math . round (
1338
+ Math . max (
1339
+ ...entries . map (
1340
+ ( e ) => e . span . startTime . epoch + e . span . duration ,
1341
+ ) ,
1342
+ ) - trace . input . startTime . epoch ,
1343
+ )
1344
+ : 0
1345
+ const totalSpanCount = entries . length
1346
+ const hasErrorSpan = entries . some (
1347
+ ( e ) =>
1348
+ e . span . status === 'error' && ! isSuppressedError ( trace , e ) ,
1349
+ )
1350
+ const hasSuppressedErrorSpan = entries . some (
1351
+ ( e ) => e . span . status === 'error' && isSuppressedError ( trace , e ) ,
1352
+ )
1353
+ return {
1354
+ ...prevTrace ,
1355
+ liveDuration,
1356
+ totalSpanCount,
1357
+ hasErrorSpan,
1358
+ hasSuppressedErrorSpan,
1359
+ }
1360
+ } ) ,
1361
+ )
1349
1362
} )
1350
1363
1351
1364
// Subscribe to definition-modified for modification indicator
1352
1365
const defModSub = traceManager
1353
1366
. when ( 'definition-modified' )
1354
1367
. subscribe ( ( event ) => {
1355
- setCurrentTrace ( ( prevTrace ) => {
1356
- if ( ! prevTrace ) return prevTrace
1357
- if ( event . traceContext . input . id !== prevTrace . traceId )
1358
- return prevTrace
1359
- return {
1360
- ...prevTrace ,
1361
- definitionModifications : [
1362
- ...( prevTrace . definitionModifications ?? [ ] ) ,
1363
- event . modifications ,
1364
- ] ,
1365
- }
1366
- } )
1368
+ schedule (
1369
+ ( ) =>
1370
+ void setCurrentTrace ( ( prevTrace ) => {
1371
+ if ( ! prevTrace ) return prevTrace
1372
+ if ( event . traceContext . input . id !== prevTrace . traceId )
1373
+ return prevTrace
1374
+ return {
1375
+ ...prevTrace ,
1376
+ definitionModifications : [
1377
+ ...( prevTrace . definitionModifications ?? [ ] ) ,
1378
+ event . modifications ,
1379
+ ] ,
1380
+ }
1381
+ } ) ,
1382
+ )
1367
1383
} )
1368
1384
1369
1385
return ( ) => {
0 commit comments