Skip to content

Commit 15b68ba

Browse files
add test displaying NDE from 1.11.3 replay
1 parent 4a99cee commit 15b68ba

File tree

7 files changed

+347
-3
lines changed

7 files changed

+347
-3
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
{
2+
"events": [
3+
{
4+
"eventId": "1",
5+
"eventTime": "2025-10-17T12:56:44.200769Z",
6+
"eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED",
7+
"taskId": "1049716",
8+
"workflowExecutionStartedEventAttributes": {
9+
"workflowType": {
10+
"name": "signalStartOtel"
11+
},
12+
"taskQueue": {
13+
"name": "test-otel-inbound",
14+
"kind": "TASK_QUEUE_KIND_NORMAL"
15+
},
16+
"input": {},
17+
"workflowTaskTimeout": "10s",
18+
"originalExecutionRunId": "10b7e171-0ee7-4775-ad6d-f5df09aa4160",
19+
"identity": "82936@mac.lan",
20+
"firstExecutionRunId": "10b7e171-0ee7-4775-ad6d-f5df09aa4160",
21+
"attempt": 1,
22+
"firstWorkflowTaskBackoff": "0s",
23+
"header": {
24+
"fields": {}
25+
},
26+
"workflowId": "f61035b7-9fa3-4120-ac03-98763ccd469a"
27+
}
28+
},
29+
{
30+
"eventId": "2",
31+
"eventTime": "2025-10-17T12:56:44.200815Z",
32+
"eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED",
33+
"taskId": "1049717",
34+
"workflowExecutionSignaledEventAttributes": {
35+
"signalName": "startSignal",
36+
"input": {},
37+
"identity": "82936@mac.lan",
38+
"header": {
39+
"fields": {}
40+
}
41+
}
42+
},
43+
{
44+
"eventId": "3",
45+
"eventTime": "2025-10-17T12:56:44.200819Z",
46+
"eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED",
47+
"taskId": "1049718",
48+
"workflowTaskScheduledEventAttributes": {
49+
"taskQueue": {
50+
"name": "test-otel-inbound",
51+
"kind": "TASK_QUEUE_KIND_NORMAL"
52+
},
53+
"startToCloseTimeout": "10s",
54+
"attempt": 1
55+
}
56+
},
57+
{
58+
"eventId": "4",
59+
"eventTime": "2025-10-17T12:56:44.201794Z",
60+
"eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED",
61+
"taskId": "1049722",
62+
"workflowTaskStartedEventAttributes": {
63+
"scheduledEventId": "3",
64+
"identity": "82936@mac.lan",
65+
"requestId": "488319d7-d425-44eb-b5ce-362f8462be1f",
66+
"historySizeBytes": "327",
67+
"workerVersion": {
68+
"buildId": "@temporalio/worker@1.13.1+6b92c11c4f907379345c3513a5f749c90d752cfd0a3bf888bf0be04350bb0d2e"
69+
}
70+
}
71+
},
72+
{
73+
"eventId": "5",
74+
"eventTime": "2025-10-17T12:56:44.229959Z",
75+
"eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED",
76+
"taskId": "1049726",
77+
"workflowTaskCompletedEventAttributes": {
78+
"scheduledEventId": "3",
79+
"startedEventId": "4",
80+
"identity": "82936@mac.lan",
81+
"workerVersion": {
82+
"buildId": "@temporalio/worker@1.13.1+6b92c11c4f907379345c3513a5f749c90d752cfd0a3bf888bf0be04350bb0d2e"
83+
},
84+
"sdkMetadata": {
85+
"coreUsedFlags": [
86+
1,
87+
3,
88+
2
89+
],
90+
"langUsedFlags": [
91+
2
92+
],
93+
"sdkName": "temporal-typescript",
94+
"sdkVersion": "1.13.1"
95+
},
96+
"meteringMetadata": {}
97+
}
98+
},
99+
{
100+
"eventId": "6",
101+
"eventTime": "2025-10-17T12:56:44.229985Z",
102+
"eventType": "EVENT_TYPE_MARKER_RECORDED",
103+
"taskId": "1049727",
104+
"markerRecordedEventAttributes": {
105+
"details": {
106+
"data": {
107+
"payloads": [
108+
{
109+
"metadata": {
110+
"encoding": "anNvbi9wbGFpbg=="
111+
},
112+
"data": "eyJzZXEiOjEsImF0dGVtcHQiOjEsImFjdGl2aXR5X2lkIjoiMSIsImFjdGl2aXR5X3R5cGUiOiJhIiwiY29tcGxldGVfdGltZSI6eyJzZWNvbmRzIjoxNzYwNzA1ODA0LCJuYW5vcyI6MjAyMzY4NjY3fSwiYmFja29mZiI6bnVsbCwib3JpZ2luYWxfc2NoZWR1bGVfdGltZSI6eyJzZWNvbmRzIjoxNzYwNzA1ODA0LCJuYW5vcyI6MjI0MTE2MDAwfX0="
113+
}
114+
]
115+
},
116+
"result": {
117+
"payloads": [
118+
{
119+
"metadata": {
120+
"encoding": "anNvbi9wbGFpbg=="
121+
},
122+
"data": "ImEi"
123+
}
124+
]
125+
}
126+
},
127+
"markerName": "core_local_activity",
128+
"workflowTaskCompletedEventId": "5"
129+
}
130+
},
131+
{
132+
"eventId": "7",
133+
"eventTime": "2025-10-17T12:56:44.229986Z",
134+
"eventType": "EVENT_TYPE_MARKER_RECORDED",
135+
"taskId": "1049728",
136+
"markerRecordedEventAttributes": {
137+
"details": {
138+
"result": {
139+
"payloads": [
140+
{
141+
"metadata": {
142+
"encoding": "anNvbi9wbGFpbg=="
143+
},
144+
"data": "ImIi"
145+
}
146+
]
147+
},
148+
"data": {
149+
"payloads": [
150+
{
151+
"metadata": {
152+
"encoding": "anNvbi9wbGFpbg=="
153+
},
154+
"data": "eyJzZXEiOjIsImF0dGVtcHQiOjEsImFjdGl2aXR5X2lkIjoiMiIsImFjdGl2aXR5X3R5cGUiOiJiIiwiY29tcGxldGVfdGltZSI6eyJzZWNvbmRzIjoxNzYwNzA1ODA0LCJuYW5vcyI6MjAyNjc1OTE3fSwiYmFja29mZiI6bnVsbCwib3JpZ2luYWxfc2NoZWR1bGVfdGltZSI6eyJzZWNvbmRzIjoxNzYwNzA1ODA0LCJuYW5vcyI6MjI3MzQ4MDAwfX0="
155+
}
156+
]
157+
}
158+
},
159+
"markerName": "core_local_activity",
160+
"workflowTaskCompletedEventId": "5"
161+
}
162+
},
163+
{
164+
"eventId": "8",
165+
"eventTime": "2025-10-17T12:56:44.230034Z",
166+
"eventType": "EVENT_TYPE_MARKER_RECORDED",
167+
"taskId": "1049729",
168+
"markerRecordedEventAttributes": {
169+
"details": {
170+
"data": {
171+
"payloads": [
172+
{
173+
"metadata": {
174+
"encoding": "anNvbi9wbGFpbg=="
175+
},
176+
"data": "eyJzZXEiOjMsImF0dGVtcHQiOjEsImFjdGl2aXR5X2lkIjoiMyIsImFjdGl2aXR5X3R5cGUiOiJjIiwiY29tcGxldGVfdGltZSI6eyJzZWNvbmRzIjoxNzYwNzA1ODA0LCJuYW5vcyI6MjAyNzI0ODM0fSwiYmFja29mZiI6bnVsbCwib3JpZ2luYWxfc2NoZWR1bGVfdGltZSI6eyJzZWNvbmRzIjoxNzYwNzA1ODA0LCJuYW5vcyI6MjI3MzU2MDAwfX0="
177+
}
178+
]
179+
},
180+
"result": {
181+
"payloads": [
182+
{
183+
"metadata": {
184+
"encoding": "anNvbi9wbGFpbg=="
185+
},
186+
"data": "ImMi"
187+
}
188+
]
189+
}
190+
},
191+
"markerName": "core_local_activity",
192+
"workflowTaskCompletedEventId": "5"
193+
}
194+
},
195+
{
196+
"eventId": "9",
197+
"eventTime": "2025-10-17T12:56:44.230036Z",
198+
"eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED",
199+
"taskId": "1049730",
200+
"workflowExecutionCompletedEventAttributes": {
201+
"result": {
202+
"payloads": [
203+
{
204+
"metadata": {
205+
"encoding": "anNvbi9wbGFpbg=="
206+
},
207+
"data": "ImFiYyI="
208+
}
209+
]
210+
},
211+
"workflowTaskCompletedEventId": "5"
212+
}
213+
}
214+
]
215+
}

packages/test/src/helpers-integration.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import {
66
WorkflowFailedError,
77
WorkflowHandle,
88
WorkflowHandleWithFirstExecutionRunId,
9+
WorkflowHandleWithSignaledRunId,
910
WorkflowStartOptions,
1011
WorkflowUpdateFailedError,
12+
WorkflowSignalWithStartOptionsWithArgs,
1113
} from '@temporalio/client';
1214
import {
1315
LocalTestWorkflowEnvironmentOptions,
@@ -195,6 +197,16 @@ export interface Helpers {
195197
fn: T,
196198
opts: Omit<WorkflowStartOptions, 'taskQueue' | 'workflowId'> & Partial<Pick<WorkflowStartOptions, 'workflowId'>>
197199
): Promise<WorkflowHandleWithFirstExecutionRunId<T>>;
200+
signalWithStart<T extends workflow.Workflow, U extends any[]>(
201+
fn: T,
202+
signal: workflow.SignalDefinition<U>
203+
): Promise<WorkflowHandleWithSignaledRunId<T>>;
204+
signalWithStart<T extends workflow.Workflow, U extends any[]>(
205+
fn: T,
206+
signal: workflow.SignalDefinition<U>,
207+
opts: Omit<WorkflowSignalWithStartOptionsWithArgs<U>, 'taskQueue' | 'workflowId'> &
208+
Partial<Pick<WorkflowStartOptions, 'workflowId'>>
209+
): Promise<WorkflowHandleWithSignaledRunId<T>>;
198210
assertWorkflowUpdateFailed(p: Promise<any>, causeConstructor: ErrorConstructor, message?: string): Promise<void>;
199211
assertWorkflowFailedError(p: Promise<any>, causeConstructor: ErrorConstructor, message?: string): Promise<void>;
200212
updateHasBeenAdmitted(handle: WorkflowHandle<workflow.Workflow>, updateId: string): Promise<boolean>;
@@ -250,6 +262,21 @@ export function configurableHelpers<T>(
250262
...opts,
251263
});
252264
},
265+
266+
async signalWithStart(
267+
fn: workflow.Workflow,
268+
signal: workflow.SignalDefinition<any[]>,
269+
opts?: Omit<WorkflowSignalWithStartOptionsWithArgs<any[]>, 'taskQueue' | 'workflowId'> &
270+
Partial<Pick<WorkflowStartOptions, 'workflowId'>>
271+
): Promise<WorkflowHandleWithSignaledRunId<workflow.Workflow>> {
272+
return await testEnv.client.workflow.signalWithStart(fn, {
273+
signal,
274+
taskQueue,
275+
workflowId: randomUUID(),
276+
...opts,
277+
});
278+
},
279+
253280
async assertWorkflowUpdateFailed(
254281
p: Promise<any>,
255282
causeConstructor: ErrorConstructor,

packages/test/src/test-integration-workflows.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import * as opentelemetry from '@opentelemetry/sdk-node';
2+
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
3+
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node';
14
import { setTimeout as setTimeoutPromise } from 'timers/promises';
25
import { randomUUID } from 'crypto';
36
import asyncRetry from 'async-retry';
@@ -49,7 +52,7 @@ import {
4952
} from './helpers-integration';
5053
import { overrideSdkInternalFlag } from './mock-internal-flags';
5154
import { heartbeatCancellationDetailsActivity } from './activities/heartbeat-cancellation-details';
52-
import { loadHistory, RUN_TIME_SKIPPING_TESTS, waitUntil } from './helpers';
55+
import { loadHistory, RUN_TIME_SKIPPING_TESTS, saveHistory, waitUntil } from './helpers';
5356

5457
const test = makeTestFunction({
5558
workflowsPath: __filename,
@@ -513,6 +516,7 @@ test("Worker doesn't request Eager Activity Dispatch if no activities are regist
513516

514517
const unblockSignal = defineSignal('unblock');
515518
const getBuildIdQuery = defineQuery<string>('getBuildId');
519+
const startSignal = defineSignal('startSignal');
516520

517521
export async function buildIdTester(): Promise<void> {
518522
let blocked = true;

packages/test/src/test-otel.ts

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import { SpanStatusCode } from '@opentelemetry/api';
88
import { ExportResultCode } from '@opentelemetry/core';
99
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
1010
import * as opentelemetry from '@opentelemetry/sdk-node';
11-
import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
11+
import {
12+
BasicTracerProvider,
13+
ConsoleSpanExporter,
14+
InMemorySpanExporter,
15+
SimpleSpanProcessor,
16+
} from '@opentelemetry/sdk-trace-base';
1217
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
1318
import test from 'ava';
1419
import { v4 as uuid4 } from 'uuid';
@@ -24,8 +29,9 @@ import {
2429
import { OpenTelemetrySinks, SpanName, SPAN_DELIMITER } from '@temporalio/interceptors-opentelemetry/lib/workflow';
2530
import { DefaultLogger, InjectedSinks, Runtime } from '@temporalio/worker';
2631
import * as activities from './activities';
27-
import { RUN_INTEGRATION_TESTS, TestWorkflowEnvironment, Worker } from './helpers';
32+
import { loadHistory, RUN_INTEGRATION_TESTS, saveHistory, TestWorkflowEnvironment, Worker } from './helpers';
2833
import * as workflows from './workflows';
34+
import { createTestWorkflowBundle } from './helpers-integration';
2935

3036
async function withFakeGrpcServer(
3137
fn: (port: number) => Promise<void>,
@@ -510,3 +516,65 @@ if (RUN_INTEGRATION_TESTS) {
510516
t.is(spans[2].status.code, SpanStatusCode.OK);
511517
});
512518
}
519+
520+
test('Can replay otel history from 1.11.3', async (t) => {
521+
const staticResource = new opentelemetry.resources.Resource({
522+
[SemanticResourceAttributes.SERVICE_NAME]: 'ts-test-otel-worker',
523+
});
524+
const worker = await Worker.create({
525+
workflowsPath: require.resolve('./workflows/signal-start-otel'),
526+
activities: {
527+
a: async () => 'a',
528+
b: async () => 'b',
529+
c: async () => 'c',
530+
},
531+
taskQueue: 'test-otel-inbound',
532+
sinks: {
533+
exporter: makeWorkflowExporter(new InMemorySpanExporter(), staticResource),
534+
},
535+
interceptors: {
536+
workflowModules: [require.resolve('./workflows/signal-start-otel')],
537+
activity: [
538+
(ctx) => ({
539+
inbound: new OpenTelemetryActivityInboundInterceptor(ctx),
540+
}),
541+
],
542+
},
543+
});
544+
const client = new WorkflowClient();
545+
546+
/*
547+
const result = await worker.runUntil(async () => {
548+
const handle = await client.signalWithStart(workflows.signalStartOtel, {
549+
signal: workflows.startSignal,
550+
taskQueue: 'test-otel-inbound',
551+
workflowId: uuid4(),
552+
});
553+
const result = await handle.result();
554+
const history = await handle.fetchHistory();
555+
await saveHistory('otel_current.json', history);
556+
return result;
557+
});
558+
*/
559+
560+
const hist = await loadHistory('otel_1_11_3.json');
561+
Worker.runReplayHistory(
562+
{
563+
workflowBundle: await createTestWorkflowBundle({
564+
workflowsPath: require.resolve('./workflows/signal-start-otel'),
565+
workflowInterceptorModules: [require.resolve('./workflows/signal-start-otel')],
566+
}),
567+
interceptors: {
568+
workflowModules: [require.resolve('./workflows/otel-interceptors')],
569+
activity: [
570+
(ctx) => ({
571+
inbound: new OpenTelemetryActivityInboundInterceptor(ctx),
572+
}),
573+
],
574+
},
575+
},
576+
hist
577+
);
578+
// t.is('abc', result);
579+
t.pass();
580+
});

packages/test/src/workflows/inbound-signal.ts

Whitespace-only changes.

packages/test/src/workflows/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export * from './shared-cancellation-scopes';
6565
export * from './noncancellable-awaited-in-root-scope';
6666
export * from './noncancellable-in-noncancellable';
6767
export * from './signal-handlers-clear';
68+
export * from './signal-start-otel';
6869
export * from './signal-target';
6970
export * from './signals-are-always-processed';
7071
export * from './signals-ordering';

0 commit comments

Comments
 (0)