@@ -980,19 +980,8 @@ export class Activator implements ActivationHandler {
980980
981981 const signalExecutionNum = this . signalHandlerExecutionSeq ++ ;
982982 this . inProgressSignals . set ( signalExecutionNum , { name : signalName , unfinishedPolicy } ) ;
983- const injectYield = shouldInjectYield ( this . sdkVersion ) ;
984- const addedInterceptor : WorkflowInterceptors [ 'inbound' ] = injectYield
985- ? [
986- {
987- handleSignal : async ( input , next ) => {
988- await Promise . resolve ( ) ;
989- return next ( input ) ;
990- } ,
991- } ,
992- ]
993- : [ ] ;
994983 const execute = composeInterceptors (
995- [ ... addedInterceptor , ... interceptors ] ,
984+ this . maybeInjectYieldForOtelHandler ( interceptors ) ,
996985 'handleSignal' ,
997986 this . signalWorkflowNextHandler . bind ( this )
998987 ) ;
@@ -1272,6 +1261,31 @@ export class Activator implements ActivationHandler {
12721261 failureToError ( failure : ProtoFailure ) : Error {
12731262 return this . failureConverter . failureToError ( failure , this . payloadConverter ) ;
12741263 }
1264+
1265+ private maybeInjectYieldForOtelHandler (
1266+ interceptors : NonNullable < WorkflowInterceptors [ 'inbound' ] >
1267+ ) : NonNullable < WorkflowInterceptors [ 'inbound' ] > {
1268+ if ( ! this . info . unsafe . isReplaying || ! shouldInjectYield ( this . sdkVersion ) ) {
1269+ return [ ...interceptors ] ;
1270+ }
1271+ const otelInboundInterceptorIndex = findOpenTelemetryInboundInterceptor ( interceptors ) ;
1272+ if ( otelInboundInterceptorIndex === null ) {
1273+ return [ ...interceptors ] ;
1274+ }
1275+ // A handler that only serves the insert a yield point in the interceptor handlers
1276+ const yieldHandleSignalInterceptor : NonNullable < WorkflowInterceptors [ 'inbound' ] > [ number ] = {
1277+ handleSignal : async ( input , next ) => {
1278+ await Promise . resolve ( ) ;
1279+ return next ( input ) ;
1280+ } ,
1281+ } ;
1282+ // Insert the yield handler before the OTEL one to synthesize the yield point added in the affected versions of the handler
1283+ return [
1284+ ...interceptors . slice ( 0 , otelInboundInterceptorIndex ) ,
1285+ yieldHandleSignalInterceptor ,
1286+ ...interceptors . slice ( otelInboundInterceptorIndex ) ,
1287+ ] ;
1288+ }
12751289}
12761290
12771291function getSeq < T extends { seq ?: number | null } > ( activation : T ) : number {
@@ -1323,22 +1337,47 @@ then you can disable this warning by passing an option when setting the handler:
13231337 ) } `;
13241338}
13251339
1340+ // Should only get run on replay
13261341function shouldInjectYield ( version ?: string ) : boolean {
13271342 if ( ! version ) {
13281343 return false ;
13291344 }
1330- const [ major , minor , patch ] = version . split ( '.' ) ;
1345+ const [ major , minor , patchAndTags ] = version . split ( '.' , 3 ) ;
13311346 // 1.11.5 - 1.13.1: need to inject
13321347 if ( major !== '1' ) return false ;
13331348
1349+ // patch might have some extra stuff that needs cleaning
1350+ // basically "takeWhile digit"
1351+ let patch ;
1352+ try {
1353+ const patchDigits = / [ 0 - 9 ] + / . exec ( patchAndTags ) ?. [ 0 ] ;
1354+ patch = patchDigits ? Number . parseInt ( patchDigits ) : null ;
1355+ } catch {
1356+ patch = null ;
1357+ }
1358+
13341359 switch ( minor ) {
13351360 case '11' :
1336- return patch === '5' ;
1361+ // 1.11.3 was the last release that didn't inject a yield point
1362+ return Boolean ( patch && patch > 3 ) ;
13371363 case '12' :
1364+ // Every 1.12 release requires a yield
13381365 return true ;
13391366 case '13' :
1340- return patch === '1' ;
1367+ // 1.13.2 will be the first release since 1.11.3 that doesn't have a yield point in `handleSignal`
1368+ return Boolean ( patch && patch < 2 ) ;
13411369 default :
13421370 return false ;
13431371 }
13441372}
1373+
1374+ function findOpenTelemetryInboundInterceptor (
1375+ interceptors : NonNullable < WorkflowInterceptors [ 'inbound' ] >
1376+ ) : number | null {
1377+ const index = interceptors . findIndex (
1378+ ( interceptor ) =>
1379+ // We use a marker instead of `instanceof` to avoid taking a dependency on @temporalio/interceptors-opentelemetry
1380+ ( interceptor as NonNullable < WorkflowInterceptors [ 'inbound' ] > & { maybeInjectYield : boolean } ) . maybeInjectYield
1381+ ) ;
1382+ return index !== - 1 ? index : null ;
1383+ }
0 commit comments