@proompteng/temporal-bun-sdk 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +46 -10
  2. package/dist/src/bin/replay-command.d.ts.map +1 -1
  3. package/dist/src/bin/replay-command.js +6 -2
  4. package/dist/src/bin/replay-command.js.map +1 -1
  5. package/dist/src/bin/temporal-bun.d.ts +1 -1
  6. package/dist/src/bin/temporal-bun.d.ts.map +1 -1
  7. package/dist/src/bin/temporal-bun.js +74 -0
  8. package/dist/src/bin/temporal-bun.js.map +1 -1
  9. package/dist/src/client/layer.d.ts +2 -2
  10. package/dist/src/client/layer.d.ts.map +1 -1
  11. package/dist/src/client/retries.d.ts.map +1 -1
  12. package/dist/src/client/retries.js +27 -3
  13. package/dist/src/client/retries.js.map +1 -1
  14. package/dist/src/client/serialization.d.ts +4 -1
  15. package/dist/src/client/serialization.d.ts.map +1 -1
  16. package/dist/src/client/serialization.js +2 -2
  17. package/dist/src/client/serialization.js.map +1 -1
  18. package/dist/src/client.d.ts +12 -4
  19. package/dist/src/client.d.ts.map +1 -1
  20. package/dist/src/client.js +270 -63
  21. package/dist/src/client.js.map +1 -1
  22. package/dist/src/common/payloads/codecs.d.ts +38 -0
  23. package/dist/src/common/payloads/codecs.d.ts.map +1 -0
  24. package/dist/src/common/payloads/codecs.js +174 -0
  25. package/dist/src/common/payloads/codecs.js.map +1 -0
  26. package/dist/src/common/payloads/converter.d.ts +52 -3
  27. package/dist/src/common/payloads/converter.d.ts.map +1 -1
  28. package/dist/src/common/payloads/converter.js +340 -2
  29. package/dist/src/common/payloads/converter.js.map +1 -1
  30. package/dist/src/common/payloads/failure.d.ts +5 -6
  31. package/dist/src/common/payloads/failure.d.ts.map +1 -1
  32. package/dist/src/common/payloads/failure.js +3 -52
  33. package/dist/src/common/payloads/failure.js.map +1 -1
  34. package/dist/src/common/payloads/index.d.ts +1 -0
  35. package/dist/src/common/payloads/index.d.ts.map +1 -1
  36. package/dist/src/common/payloads/index.js +1 -0
  37. package/dist/src/common/payloads/index.js.map +1 -1
  38. package/dist/src/config.d.ts +9 -0
  39. package/dist/src/config.d.ts.map +1 -1
  40. package/dist/src/config.js +62 -1
  41. package/dist/src/config.js.map +1 -1
  42. package/dist/src/interceptors/client.d.ts +28 -0
  43. package/dist/src/interceptors/client.d.ts.map +1 -0
  44. package/dist/src/interceptors/client.js +169 -0
  45. package/dist/src/interceptors/client.js.map +1 -0
  46. package/dist/src/interceptors/types.d.ts +33 -0
  47. package/dist/src/interceptors/types.d.ts.map +1 -0
  48. package/dist/src/interceptors/types.js +44 -0
  49. package/dist/src/interceptors/types.js.map +1 -0
  50. package/dist/src/interceptors/worker.d.ts +22 -0
  51. package/dist/src/interceptors/worker.d.ts.map +1 -0
  52. package/dist/src/interceptors/worker.js +156 -0
  53. package/dist/src/interceptors/worker.js.map +1 -0
  54. package/dist/src/runtime/cli-layer.d.ts +4 -3
  55. package/dist/src/runtime/cli-layer.d.ts.map +1 -1
  56. package/dist/src/runtime/cli-layer.js +5 -2
  57. package/dist/src/runtime/cli-layer.js.map +1 -1
  58. package/dist/src/runtime/effect-layers.d.ts +9 -0
  59. package/dist/src/runtime/effect-layers.d.ts.map +1 -1
  60. package/dist/src/runtime/effect-layers.js +15 -0
  61. package/dist/src/runtime/effect-layers.js.map +1 -1
  62. package/dist/src/worker/runtime.d.ts +5 -0
  63. package/dist/src/worker/runtime.d.ts.map +1 -1
  64. package/dist/src/worker/runtime.js +207 -12
  65. package/dist/src/worker/runtime.js.map +1 -1
  66. package/dist/src/worker/sticky-cache.d.ts +5 -0
  67. package/dist/src/worker/sticky-cache.d.ts.map +1 -1
  68. package/dist/src/worker/sticky-cache.js +26 -0
  69. package/dist/src/worker/sticky-cache.js.map +1 -1
  70. package/dist/src/worker/update-protocol.d.ts.map +1 -1
  71. package/dist/src/worker/update-protocol.js +15 -0
  72. package/dist/src/worker/update-protocol.js.map +1 -1
  73. package/dist/src/worker.js +1 -0
  74. package/dist/src/worker.js.map +1 -1
  75. package/dist/src/workflow/commands.d.ts +38 -2
  76. package/dist/src/workflow/commands.d.ts.map +1 -1
  77. package/dist/src/workflow/commands.js +153 -1
  78. package/dist/src/workflow/commands.js.map +1 -1
  79. package/dist/src/workflow/context.d.ts +59 -2
  80. package/dist/src/workflow/context.d.ts.map +1 -1
  81. package/dist/src/workflow/context.js +317 -7
  82. package/dist/src/workflow/context.js.map +1 -1
  83. package/dist/src/workflow/determinism.d.ts +5 -0
  84. package/dist/src/workflow/determinism.d.ts.map +1 -1
  85. package/dist/src/workflow/determinism.js +45 -3
  86. package/dist/src/workflow/determinism.js.map +1 -1
  87. package/dist/src/workflow/errors.d.ts +3 -0
  88. package/dist/src/workflow/errors.d.ts.map +1 -1
  89. package/dist/src/workflow/errors.js +6 -0
  90. package/dist/src/workflow/errors.js.map +1 -1
  91. package/dist/src/workflow/executor.d.ts +3 -0
  92. package/dist/src/workflow/executor.d.ts.map +1 -1
  93. package/dist/src/workflow/executor.js +70 -10
  94. package/dist/src/workflow/executor.js.map +1 -1
  95. package/dist/src/workflow/replay.d.ts.map +1 -1
  96. package/dist/src/workflow/replay.js +220 -1
  97. package/dist/src/workflow/replay.js.map +1 -1
  98. package/package.json +1 -1
@@ -6,10 +6,11 @@ import { Cause, Effect, Exit, Fiber } from 'effect';
6
6
  import { makeActivityLifecycle, } from '../activities/lifecycle';
7
7
  import { buildTransportOptions, normalizeTemporalAddress } from '../client';
8
8
  import { durationFromMillis, durationToMillis } from '../common/duration';
9
- import { createDefaultDataConverter, decodePayloadsToValues, encodeValuesToPayloads, } from '../common/payloads/converter';
9
+ import { buildCodecsFromConfig, createDefaultDataConverter, decodePayloadsToValues, encodeValuesToPayloads, } from '../common/payloads/converter';
10
10
  import { encodeErrorToFailure, encodeFailurePayloads, failureToError } from '../common/payloads/failure';
11
11
  import { sleep } from '../common/sleep';
12
12
  import { loadTemporalConfig } from '../config';
13
+ import { makeDefaultWorkerInterceptors, runWorkerInterceptors, } from '../interceptors/worker';
13
14
  import { createObservabilityServices } from '../observability';
14
15
  import { CommandSchema, RecordMarkerCommandAttributesSchema, } from '../proto/temporal/api/command/v1/message_pb';
15
16
  import { PayloadsSchema, WorkflowExecutionSchema, } from '../proto/temporal/api/common/v1/message_pb';
@@ -66,7 +67,6 @@ const COMPLETION_COMMAND_TYPES = new Set([
66
67
  export class WorkerRuntime {
67
68
  static async create(options = {}) {
68
69
  const config = options.config ?? (await loadTemporalConfig());
69
- const dataConverter = options.dataConverter ?? createDefaultDataConverter();
70
70
  const namespace = options.namespace ?? config.namespace;
71
71
  if (!namespace) {
72
72
  throw new Error('Temporal namespace must be provided');
@@ -80,12 +80,6 @@ export class WorkerRuntime {
80
80
  if (workflows.length === 0) {
81
81
  throw new Error('No workflow definitions were registered; provide workflows or workflowsPath');
82
82
  }
83
- const registry = new WorkflowRegistry();
84
- registry.registerMany(workflows);
85
- const executor = new WorkflowExecutor({
86
- registry,
87
- dataConverter,
88
- });
89
83
  const activities = options.activities ?? {};
90
84
  const observability = await Effect.runPromise(createObservabilityServices({
91
85
  logLevel: config.logLevel,
@@ -97,6 +91,18 @@ export class WorkerRuntime {
97
91
  metricsExporter: options.metricsExporter,
98
92
  }));
99
93
  const { logger, metricsRegistry, metricsExporter } = observability;
94
+ const dataConverter = options.dataConverter ??
95
+ createDefaultDataConverter({
96
+ payloadCodecs: buildCodecsFromConfig(config.payloadCodecs),
97
+ logger,
98
+ metricsRegistry,
99
+ });
100
+ const registry = new WorkflowRegistry();
101
+ registry.registerMany(workflows);
102
+ const executor = new WorkflowExecutor({
103
+ registry,
104
+ dataConverter,
105
+ });
100
106
  const runtimeMetrics = await WorkerRuntime.#initMetrics(metricsRegistry);
101
107
  let workflowService;
102
108
  if (options.workflowService) {
@@ -181,6 +187,22 @@ export class WorkerRuntime {
181
187
  }));
182
188
  }
183
189
  }
190
+ const tracingEnabled = options.tracingEnabled ?? config.tracingInterceptorsEnabled ?? false;
191
+ const workerInterceptorBuilder = options.interceptorBuilder ?? {
192
+ build: (input) => makeDefaultWorkerInterceptors(input),
193
+ };
194
+ const defaultWorkerInterceptors = await Effect.runPromise(workerInterceptorBuilder.build({
195
+ namespace,
196
+ taskQueue,
197
+ identity,
198
+ buildId,
199
+ logger,
200
+ metricsRegistry,
201
+ metricsExporter,
202
+ dataConverter,
203
+ tracingEnabled,
204
+ }));
205
+ const workerInterceptors = [...defaultWorkerInterceptors, ...(options.interceptors ?? [])];
184
206
  const activityLifecycle = await Effect.runPromise(makeActivityLifecycle({
185
207
  heartbeatIntervalMs: config.activityHeartbeatIntervalMs,
186
208
  heartbeatRpcTimeoutMs: config.activityHeartbeatRpcTimeoutMs,
@@ -233,6 +255,7 @@ export class WorkerRuntime {
233
255
  versioningBehavior,
234
256
  stickySchedulingEnabled,
235
257
  workflowPollerCount,
258
+ interceptors: workerInterceptors,
236
259
  });
237
260
  }
238
261
  #config;
@@ -248,6 +271,7 @@ export class WorkerRuntime {
248
271
  #namespace;
249
272
  #taskQueue;
250
273
  #identity;
274
+ #interceptors;
251
275
  #activityLifecycle;
252
276
  #scheduler;
253
277
  #stickyCache;
@@ -275,6 +299,7 @@ export class WorkerRuntime {
275
299
  this.#namespace = params.namespace;
276
300
  this.#taskQueue = params.taskQueue;
277
301
  this.#identity = params.identity;
302
+ this.#interceptors = params.interceptors;
278
303
  this.#activityLifecycle = params.activityLifecycle;
279
304
  this.#scheduler = params.scheduler;
280
305
  this.#stickyCache = params.stickyCache;
@@ -353,6 +378,10 @@ export class WorkerRuntime {
353
378
  workflowTaskCompleted: await makeCounter('temporal_worker_workflow_tasks_completed_total', 'Workflow tasks completed by the scheduler'),
354
379
  activityTaskStarted: await makeCounter('temporal_worker_activity_tasks_started_total', 'Activity tasks dispatched to the scheduler'),
355
380
  activityTaskCompleted: await makeCounter('temporal_worker_activity_tasks_completed_total', 'Activity tasks completed by the scheduler'),
381
+ queryTaskStarted: await makeCounter('temporal_worker_query_started_total', 'Query-only workflow tasks dispatched to the scheduler'),
382
+ queryTaskCompleted: await makeCounter('temporal_worker_query_completed_total', 'Query-only workflow tasks completed successfully'),
383
+ queryTaskFailed: await makeCounter('temporal_worker_query_failed_total', 'Query-only workflow tasks responded with failure'),
384
+ queryTaskLatency: await makeHistogram('temporal_worker_query_latency_ms', 'End-to-end workflow query latency (ms)'),
356
385
  };
357
386
  }
358
387
  async run() {
@@ -514,17 +543,38 @@ export class WorkerRuntime {
514
543
  #isRpcAbortError(error) {
515
544
  return isAbortError(error) || (error instanceof ConnectError && error.code === Code.Canceled);
516
545
  }
546
+ #isBenignPollTimeout(error) {
547
+ if (error instanceof ConnectError) {
548
+ return error.code === Code.DeadlineExceeded || error.code === Code.Canceled;
549
+ }
550
+ if (error instanceof Error) {
551
+ const msg = error.message.toLowerCase();
552
+ return msg.includes('deadline') && msg.includes('exceeded');
553
+ }
554
+ if (typeof error === 'string') {
555
+ const msg = error.toLowerCase();
556
+ return msg.includes('deadline') && msg.includes('exceeded');
557
+ }
558
+ return false;
559
+ }
517
560
  async #enqueueActivityTask(response) {
518
561
  const taskToken = response.taskToken ?? new Uint8Array();
519
562
  const envelope = {
520
563
  taskToken,
521
- handler: () => this.#processActivityTask(response),
564
+ handler: () => this.#runActivityTask(response),
522
565
  args: [],
523
566
  };
524
567
  await Effect.runPromise(this.#scheduler.enqueueActivity(envelope));
525
568
  }
526
569
  #handleWorkflowPollerError(queueName, error) {
527
570
  return Effect.promise(async () => {
571
+ if (this.#isBenignPollTimeout(error)) {
572
+ this.#log('debug', 'workflow poll timeout (no tasks)', {
573
+ queueName,
574
+ namespace: this.#namespace,
575
+ });
576
+ return;
577
+ }
528
578
  this.#incrementCounter(this.#metrics.workflowPollErrors);
529
579
  this.#log('warn', 'workflow polling failed', {
530
580
  queueName,
@@ -536,6 +586,13 @@ export class WorkerRuntime {
536
586
  }
537
587
  #handleActivityPollerError(error) {
538
588
  return Effect.promise(async () => {
589
+ if (this.#isBenignPollTimeout(error)) {
590
+ this.#log('debug', 'activity poll timeout (no tasks)', {
591
+ namespace: this.#namespace,
592
+ taskQueue: this.#taskQueue,
593
+ });
594
+ return;
595
+ }
539
596
  this.#incrementCounter(this.#metrics.activityPollErrors);
540
597
  this.#log('warn', 'activity polling failed', {
541
598
  namespace: this.#namespace,
@@ -547,7 +604,40 @@ export class WorkerRuntime {
547
604
  }
548
605
  async #handleWorkflowTask(response, nondeterminismRetry = 0) {
549
606
  const execution = this.#resolveWorkflowExecution(response);
607
+ const queryCount = response.queries && typeof response.queries === 'object' && !Array.isArray(response.queries)
608
+ ? Object.keys(response.queries).length
609
+ : Array.isArray(response.queries)
610
+ ? response.queries.length
611
+ : 0;
612
+ const hasQueryRequests = Boolean(response.query) || queryCount > 0;
613
+ const hasUpdateMessages = (response.messages?.length ?? 0) > 0;
614
+ const kind = hasUpdateMessages
615
+ ? 'worker.updateTask'
616
+ : hasQueryRequests
617
+ ? 'worker.queryTask'
618
+ : 'worker.workflowTask';
619
+ const context = {
620
+ kind,
621
+ namespace: this.#namespace,
622
+ taskQueue: this.#taskQueue,
623
+ identity: this.#identity,
624
+ buildId: this.#deploymentOptions.buildId,
625
+ workflowId: execution.workflowId,
626
+ runId: execution.runId,
627
+ attempt: Number(response.attempt ?? 1),
628
+ metadata: { nondeterminismRetry },
629
+ };
630
+ const effect = runWorkerInterceptors(this.#interceptors, context, () => Effect.tryPromise(() => this.#processWorkflowTask(response, nondeterminismRetry, execution)));
631
+ await Effect.runPromise(effect);
632
+ }
633
+ async #processWorkflowTask(response, nondeterminismRetry = 0, executionOverride) {
634
+ const execution = executionOverride ?? this.#resolveWorkflowExecution(response);
550
635
  const workflowTaskAttempt = Number(response.attempt ?? 1);
636
+ const isLegacyQueryTask = Boolean(response.query);
637
+ const queryStartTime = isLegacyQueryTask ? Date.now() : null;
638
+ if (isLegacyQueryTask) {
639
+ this.#incrementCounter(this.#metrics.queryTaskStarted);
640
+ }
551
641
  const historyEvents = await this.#collectWorkflowHistory(execution, response);
552
642
  const workflowType = this.#resolveWorkflowType(response, historyEvents);
553
643
  const args = await this.#decodeWorkflowArgs(historyEvents);
@@ -637,7 +727,8 @@ export class WorkerRuntime {
637
727
  }
638
728
  const expectedDeterminismState = previousState;
639
729
  try {
640
- const activityResults = await this.#extractActivityResolutions(historyEvents);
730
+ const { results: activityResults, scheduledEventIds: activityScheduleEventIds } = await this.#extractActivityResolutions(historyEvents);
731
+ const timerResults = await this.#extractTimerResolutions(historyEvents);
641
732
  const replayUpdates = historyReplay?.updates ?? [];
642
733
  const mergedUpdates = mergeUpdateInvocations(replayUpdates, collectedUpdates.invocations);
643
734
  const output = await this.#executor.execute({
@@ -649,9 +740,12 @@ export class WorkerRuntime {
649
740
  arguments: args,
650
741
  determinismState: previousState,
651
742
  activityResults,
743
+ activityScheduleEventIds,
652
744
  signalDeliveries,
745
+ timerResults,
653
746
  queryRequests,
654
747
  updates: mergedUpdates,
748
+ mode: isLegacyQueryTask ? 'query' : 'workflow',
655
749
  });
656
750
  this.#log('debug', 'workflow query evaluation summary', {
657
751
  ...baseLogFields,
@@ -681,10 +775,28 @@ export class WorkerRuntime {
681
775
  legacyQueryResult = entry;
682
776
  }
683
777
  }
778
+ if (isLegacyQueryTask) {
779
+ const target = legacyQueryResult ?? output.queryResults.find((entry) => entry.request.source === 'legacy');
780
+ if (!target) {
781
+ throw new Error('Legacy query result missing from workflow execution');
782
+ }
783
+ await this.#respondLegacyQueryTask(response, target);
784
+ if (queryStartTime !== null) {
785
+ this.#observeHistogram(this.#metrics.queryTaskLatency, Date.now() - queryStartTime);
786
+ }
787
+ this.#incrementCounter(this.#metrics.queryTaskCompleted);
788
+ return;
789
+ }
684
790
  const cacheBaselineEventId = this.#resolveCurrentStartedEventId(response) ?? historyReplay?.lastEventId ?? null;
685
791
  const shouldRecordMarker = output.completion === 'pending';
686
792
  let commandsForResponse = output.commands;
687
- const dispatchesForNewMessages = (output.updateDispatches ?? []).filter((dispatch) => collectedUpdates.requestsByUpdateId.has(dispatch.updateId));
793
+ const dispatchesForNewMessages = (output.updateDispatches ?? []).filter((dispatch) => {
794
+ if (dispatch.type === 'acceptance' || dispatch.type === 'rejection') {
795
+ return collectedUpdates.requestsByUpdateId.has(dispatch.updateId);
796
+ }
797
+ // Allow completion messages to be emitted even if the request metadata was seen on a prior task.
798
+ return true;
799
+ });
688
800
  const updateProtocolMessages = await buildUpdateProtocolMessages({
689
801
  dispatches: dispatchesForNewMessages,
690
802
  collected: collectedUpdates,
@@ -702,6 +814,7 @@ export class WorkerRuntime {
702
814
  }
703
815
  else {
704
816
  await this.#removeStickyEntry(stickyKey);
817
+ await this.#removeStickyEntriesForWorkflow(stickyKey.workflowId);
705
818
  this.#log('debug', 'sticky cache entry cleared (workflow completed)', baseLogFields);
706
819
  }
707
820
  }
@@ -754,12 +867,29 @@ export class WorkerRuntime {
754
867
  let stickyEntryCleared = false;
755
868
  if (stickyKey) {
756
869
  await this.#removeStickyEntry(stickyKey);
870
+ await this.#removeStickyEntriesForWorkflow(stickyKey.workflowId);
757
871
  stickyEntryCleared = true;
758
872
  }
759
873
  if (this.#isTaskNotFoundError(error)) {
760
874
  this.#logWorkflowTaskNotFound('respondWorkflowTaskCompleted', execution);
761
875
  return;
762
876
  }
877
+ if (isLegacyQueryTask) {
878
+ this.#incrementCounter(this.#metrics.queryTaskFailed);
879
+ if (queryStartTime !== null) {
880
+ this.#observeHistogram(this.#metrics.queryTaskLatency, Date.now() - queryStartTime);
881
+ }
882
+ if (error instanceof WorkflowNondeterminismError) {
883
+ const mismatches = await this.#computeNondeterminismMismatches(error, expectedDeterminismState);
884
+ this.#incrementCounter(this.#metrics.nondeterminism);
885
+ this.#log('error', 'workflow query nondeterminism detected', {
886
+ ...baseLogFields,
887
+ mismatches,
888
+ });
889
+ }
890
+ await this.#respondLegacyQueryFailure(response, error);
891
+ return;
892
+ }
763
893
  if (error instanceof WorkflowNondeterminismError) {
764
894
  const mismatches = await this.#computeNondeterminismMismatches(error, expectedDeterminismState);
765
895
  if (stickyKey && stickyEntryCleared) {
@@ -838,6 +968,7 @@ export class WorkerRuntime {
838
968
  async #extractActivityResolutions(events) {
839
969
  const resolutions = new Map();
840
970
  const scheduledActivityIds = new Map();
971
+ const activityScheduleById = new Map();
841
972
  const normalizeEventId = (value) => {
842
973
  if (value === undefined || value === null) {
843
974
  return undefined;
@@ -868,6 +999,7 @@ export class WorkerRuntime {
868
999
  const scheduledKey = normalizeEventId(event.eventId);
869
1000
  if (activityId && scheduledKey) {
870
1001
  scheduledActivityIds.set(scheduledKey, activityId);
1002
+ activityScheduleById.set(activityId, scheduledKey);
871
1003
  }
872
1004
  break;
873
1005
  }
@@ -932,7 +1064,7 @@ export class WorkerRuntime {
932
1064
  break;
933
1065
  }
934
1066
  }
935
- return resolutions;
1067
+ return { results: resolutions, scheduledEventIds: activityScheduleById };
936
1068
  }
937
1069
  async #extractSignalDeliveries(events) {
938
1070
  const deliveries = [];
@@ -970,6 +1102,22 @@ export class WorkerRuntime {
970
1102
  }
971
1103
  return deliveries;
972
1104
  }
1105
+ async #extractTimerResolutions(events) {
1106
+ const fired = new Set();
1107
+ for (const event of events) {
1108
+ if (event.eventType !== EventType.TIMER_FIRED) {
1109
+ continue;
1110
+ }
1111
+ if (event.attributes?.case !== 'timerFiredEventAttributes') {
1112
+ continue;
1113
+ }
1114
+ const attrs = event.attributes.value;
1115
+ if (attrs.timerId) {
1116
+ fired.add(attrs.timerId);
1117
+ }
1118
+ }
1119
+ return fired;
1120
+ }
973
1121
  async #extractWorkflowQueryRequests(response) {
974
1122
  const requests = [];
975
1123
  const map = response.queries ?? {};
@@ -1035,6 +1183,34 @@ export class WorkerRuntime {
1035
1183
  });
1036
1184
  await this.#workflowService.respondQueryTaskCompleted(request, { timeoutMs: RESPOND_TIMEOUT_MS });
1037
1185
  }
1186
+ async #respondLegacyQueryFailure(response, cause) {
1187
+ const failure = await encodeErrorToFailure(this.#dataConverter, cause);
1188
+ const message = cause instanceof Error ? cause.message : 'Workflow query failed';
1189
+ const request = create(RespondQueryTaskCompletedRequestSchema, {
1190
+ taskToken: response.taskToken ?? new Uint8Array(),
1191
+ completedType: QueryResultType.FAILED,
1192
+ errorMessage: message,
1193
+ namespace: this.#namespace,
1194
+ failure,
1195
+ cause: WorkflowTaskFailedCause.UNSPECIFIED,
1196
+ });
1197
+ try {
1198
+ await this.#workflowService.respondQueryTaskCompleted(request, { timeoutMs: RESPOND_TIMEOUT_MS });
1199
+ }
1200
+ catch (rpcError) {
1201
+ this.#log('error', 'respondQueryTaskCompleted failed for legacy query', {
1202
+ namespace: this.#namespace,
1203
+ workflowId: response.workflowExecution?.workflowId,
1204
+ runId: response.workflowExecution?.runId,
1205
+ error: rpcError instanceof Error ? rpcError.message : String(rpcError),
1206
+ });
1207
+ if (this.#isTaskNotFoundError(rpcError)) {
1208
+ this.#logWorkflowTaskNotFound('respondQueryTaskCompleted', this.#resolveWorkflowExecution(response));
1209
+ return;
1210
+ }
1211
+ throw rpcError;
1212
+ }
1213
+ }
1038
1214
  async #fetchWorkflowHistoryPage(execution, nextPageToken) {
1039
1215
  if (!execution.workflowId || !execution.runId) {
1040
1216
  return { events: [], nextPageToken: new Uint8Array() };
@@ -1316,6 +1492,11 @@ export class WorkerRuntime {
1316
1492
  async #removeStickyEntry(key) {
1317
1493
  await Effect.runPromise(this.#stickyCache.remove(key));
1318
1494
  }
1495
+ async #removeStickyEntriesForWorkflow(workflowId) {
1496
+ if (!workflowId)
1497
+ return;
1498
+ await Effect.runPromise(this.#stickyCache.removeByWorkflow({ namespace: this.#namespace, workflowId }));
1499
+ }
1319
1500
  async #failWorkflowTask(response, execution, error, cause = WorkflowTaskFailedCause.UNSPECIFIED) {
1320
1501
  const failure = await encodeErrorToFailure(this.#dataConverter, error);
1321
1502
  const encoded = await encodeFailurePayloads(this.#dataConverter, failure);
@@ -1339,6 +1520,20 @@ export class WorkerRuntime {
1339
1520
  throw rpcError;
1340
1521
  }
1341
1522
  }
1523
+ async #runActivityTask(response) {
1524
+ const context = {
1525
+ kind: 'worker.activityTask',
1526
+ namespace: this.#namespace,
1527
+ taskQueue: this.#taskQueue,
1528
+ identity: this.#identity,
1529
+ buildId: this.#deploymentOptions.buildId,
1530
+ workflowId: response.workflowExecution?.workflowId ?? undefined,
1531
+ runId: response.workflowExecution?.runId ?? undefined,
1532
+ attempt: Number(response.attempt ?? 1),
1533
+ };
1534
+ const effect = runWorkerInterceptors(this.#interceptors, context, () => Effect.tryPromise(() => this.#processActivityTask(response)));
1535
+ await Effect.runPromise(effect);
1536
+ }
1342
1537
  async #processActivityTask(response) {
1343
1538
  const cancelRequested = isActivityCancelRequested(response);
1344
1539
  if (cancelRequested) {