autotel 4.0.0 → 4.2.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.
- package/README.md +26 -1
- package/dist/auto.cjs +2 -2
- package/dist/auto.js +1 -1
- package/dist/correlation-id.cjs +1 -1
- package/dist/correlation-id.js +1 -1
- package/dist/decorators.cjs +1 -1
- package/dist/decorators.js +1 -1
- package/dist/{event-Dlqr4ZNL.cjs → event-BhHREDJk.cjs} +3 -3
- package/dist/{event-Dlqr4ZNL.cjs.map → event-BhHREDJk.cjs.map} +1 -1
- package/dist/{event-_58ryBjh.js → event-ByBTV9M2.js} +3 -3
- package/dist/{event-_58ryBjh.js.map → event-ByBTV9M2.js.map} +1 -1
- package/dist/event.cjs +1 -1
- package/dist/event.js +1 -1
- package/dist/{functional-BGkT8J-h.js → functional-DtI0u4vx.js} +19 -19
- package/dist/functional-DtI0u4vx.js.map +1 -0
- package/dist/{functional-C4CzoVrX.cjs → functional-zpzNLhky.cjs} +4 -4
- package/dist/{functional-C4CzoVrX.cjs.map → functional-zpzNLhky.cjs.map} +1 -1
- package/dist/functional.cjs +1 -1
- package/dist/functional.js +1 -1
- package/dist/http.cjs +1 -1
- package/dist/http.js +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/{init-DJQOdVlN.d.ts → init-B7u-DjxM.d.ts} +57 -2
- package/dist/init-B7u-DjxM.d.ts.map +1 -0
- package/dist/{init-DvapOXCc.cjs → init-BX7AmFRl.cjs} +40 -21
- package/dist/init-BX7AmFRl.cjs.map +1 -0
- package/dist/{init-Ch6t7MNI.js → init-D-jnNMix.js} +39 -20
- package/dist/init-D-jnNMix.js.map +1 -0
- package/dist/{init-CNp-ee80.d.cts → init-DSrRmVnz.d.cts} +57 -2
- package/dist/init-DSrRmVnz.d.cts.map +1 -0
- package/dist/instrumentation.cjs +1 -1
- package/dist/instrumentation.js +1 -1
- package/dist/logger-D3Ej3DII.js +446 -0
- package/dist/logger-D3Ej3DII.js.map +1 -0
- package/dist/logger-thMPLpOG.cjs +487 -0
- package/dist/logger-thMPLpOG.cjs.map +1 -0
- package/dist/logger.cjs +8 -236
- package/dist/logger.js +2 -204
- package/dist/messaging.cjs +1 -1
- package/dist/messaging.js +1 -1
- package/dist/semantic-helpers.cjs +1 -1
- package/dist/semantic-helpers.js +1 -1
- package/dist/{track-3HY4NGV-.cjs → track-D59FfpL0.cjs} +2 -2
- package/dist/{track-3HY4NGV-.cjs.map → track-D59FfpL0.cjs.map} +1 -1
- package/dist/{track-nsKVy-pj.js → track-wc0HafS_.js} +6 -6
- package/dist/track-wc0HafS_.js.map +1 -0
- package/dist/webhook.cjs +1 -1
- package/dist/webhook.js +1 -1
- package/dist/workflow-distributed.cjs +1 -1
- package/dist/workflow-distributed.js +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.js +1 -1
- package/dist/{yaml-config-B3dQ82GR.cjs → yaml-config-Ck2uB0Dp.cjs} +2 -1
- package/dist/yaml-config-Ck2uB0Dp.cjs.map +1 -0
- package/dist/yaml-config.cjs +1 -1
- package/dist/yaml-config.d.cts +7 -1
- package/dist/yaml-config.d.cts.map +1 -1
- package/dist/yaml-config.d.ts +7 -1
- package/dist/yaml-config.d.ts.map +1 -1
- package/dist/yaml-config.js +1 -0
- package/dist/yaml-config.js.map +1 -1
- package/package.json +1 -2
- package/skills/autotel-core/SKILL.md +2 -0
- package/skills/autotel-instrumentation/SKILL.md +25 -0
- package/skills/debug-missing-spans/SKILL.md +3 -1
- package/skills/migrate-to-autotel/SKILL.md +24 -23
- package/skills/review-otel-patterns/SKILL.md +5 -4
- package/dist/functional-BGkT8J-h.js.map +0 -1
- package/dist/init-CNp-ee80.d.cts.map +0 -1
- package/dist/init-Ch6t7MNI.js.map +0 -1
- package/dist/init-DJQOdVlN.d.ts.map +0 -1
- package/dist/init-DvapOXCc.cjs.map +0 -1
- package/dist/logger.cjs.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/track-nsKVy-pj.js.map +0 -1
- package/dist/yaml-config-B3dQ82GR.cjs.map +0 -1
- package/src/attribute-redacting-processor.test.ts +0 -763
- package/src/attribute-redacting-processor.ts +0 -621
- package/src/attributes/attachers.ts +0 -161
- package/src/attributes/builders.ts +0 -529
- package/src/attributes/domains.ts +0 -42
- package/src/attributes/index.ts +0 -81
- package/src/attributes/registry.ts +0 -323
- package/src/attributes/types.ts +0 -211
- package/src/attributes/utils.ts +0 -64
- package/src/attributes/validators.ts +0 -266
- package/src/attributes.test.ts +0 -292
- package/src/auto.ts +0 -67
- package/src/autotel-logger.test.ts +0 -548
- package/src/autotel-logger.ts +0 -364
- package/src/baggage-span-processor.test.ts +0 -202
- package/src/baggage-span-processor.ts +0 -100
- package/src/business-baggage.test.ts +0 -500
- package/src/business-baggage.ts +0 -669
- package/src/circuit-breaker.test.ts +0 -341
- package/src/circuit-breaker.ts +0 -184
- package/src/config.test.ts +0 -94
- package/src/config.ts +0 -172
- package/src/correlated-events.test.ts +0 -151
- package/src/correlated-events.ts +0 -47
- package/src/correlation-id.test.ts +0 -163
- package/src/correlation-id.ts +0 -206
- package/src/db.test.ts +0 -252
- package/src/db.ts +0 -447
- package/src/decorators.test.ts +0 -153
- package/src/decorators.ts +0 -188
- package/src/define-event.test.ts +0 -41
- package/src/define-event.ts +0 -58
- package/src/devtools.ts +0 -60
- package/src/drain-pipeline.test.ts +0 -68
- package/src/drain-pipeline.ts +0 -199
- package/src/drain-toolkit.test.ts +0 -113
- package/src/drain-toolkit.ts +0 -129
- package/src/enricher-toolkit.test.ts +0 -67
- package/src/enricher-toolkit.ts +0 -79
- package/src/enrichers.test.ts +0 -150
- package/src/enrichers.ts +0 -145
- package/src/env-config.test.ts +0 -323
- package/src/env-config.ts +0 -309
- package/src/error-catalog.test.ts +0 -133
- package/src/error-catalog.ts +0 -262
- package/src/event-queue.test.ts +0 -864
- package/src/event-queue.ts +0 -699
- package/src/event-subscriber.ts +0 -262
- package/src/event-testing.ts +0 -197
- package/src/event.test.ts +0 -1104
- package/src/event.ts +0 -988
- package/src/events-config.ts +0 -235
- package/src/exporters.ts +0 -165
- package/src/filtering-span-processor.test.ts +0 -281
- package/src/filtering-span-processor.ts +0 -111
- package/src/flatten-attributes.test.ts +0 -76
- package/src/flatten-attributes.ts +0 -80
- package/src/functional.strict-types.typecheck.ts +0 -53
- package/src/functional.test.ts +0 -1464
- package/src/functional.ts +0 -2539
- package/src/functional.types.test.ts +0 -135
- package/src/hook.mjs +0 -15
- package/src/http.test.ts +0 -485
- package/src/http.ts +0 -424
- package/src/index.ts +0 -433
- package/src/init-auto-redactor.test.ts +0 -53
- package/src/init-redactor.test.ts +0 -8
- package/src/init.customization.test.ts +0 -594
- package/src/init.integrations.test.ts +0 -399
- package/src/init.openllmetry.test.ts +0 -194
- package/src/init.protocol.test.ts +0 -215
- package/src/init.ts +0 -2312
- package/src/instrumentation.test.ts +0 -108
- package/src/instrumentation.ts +0 -319
- package/src/logger.test.ts +0 -125
- package/src/logger.ts +0 -341
- package/src/messaging-adapters.test.ts +0 -595
- package/src/messaging-adapters.ts +0 -583
- package/src/messaging-testing.test.ts +0 -573
- package/src/messaging-testing.ts +0 -935
- package/src/messaging.test.ts +0 -1646
- package/src/messaging.ts +0 -2245
- package/src/metric-helpers.ts +0 -47
- package/src/metric-testing.ts +0 -197
- package/src/metric.ts +0 -446
- package/src/metrics.test.ts +0 -241
- package/src/node-require.ts +0 -123
- package/src/operation-context.ts +0 -93
- package/src/parse-error.test.ts +0 -73
- package/src/parse-error.ts +0 -112
- package/src/posthog-logs.test.ts +0 -115
- package/src/posthog-logs.ts +0 -77
- package/src/pretty-console-exporter.test.ts +0 -545
- package/src/pretty-console-exporter.ts +0 -413
- package/src/pretty-log-formatter.test.ts +0 -123
- package/src/pretty-log-formatter.ts +0 -210
- package/src/processors/canonical-log-line-processor.test.ts +0 -523
- package/src/processors/canonical-log-line-processor.ts +0 -396
- package/src/processors.ts +0 -152
- package/src/rate-limiter.test.ts +0 -199
- package/src/rate-limiter.ts +0 -98
- package/src/redact-values.test.ts +0 -90
- package/src/redact-values.ts +0 -34
- package/src/register.ts +0 -37
- package/src/request-logger.test.ts +0 -545
- package/src/request-logger.ts +0 -342
- package/src/sampling.test.ts +0 -1060
- package/src/sampling.ts +0 -737
- package/src/security-schema.test.ts +0 -45
- package/src/security-schema.ts +0 -107
- package/src/semantic-conventions.ts +0 -15
- package/src/semantic-helpers.test.ts +0 -226
- package/src/semantic-helpers.ts +0 -438
- package/src/shutdown.test.ts +0 -364
- package/src/shutdown.ts +0 -246
- package/src/span-name-normalizer.test.ts +0 -377
- package/src/span-name-normalizer.ts +0 -213
- package/src/stable-hash.ts +0 -27
- package/src/structured-error.test.ts +0 -191
- package/src/structured-error.ts +0 -157
- package/src/stub.integration.test.ts +0 -361
- package/src/tail-sampling-processor.test.ts +0 -230
- package/src/tail-sampling-processor.ts +0 -55
- package/src/test-span-collector.test.ts +0 -234
- package/src/test-span-collector.ts +0 -150
- package/src/testing.ts +0 -705
- package/src/trace-context.test.ts +0 -73
- package/src/trace-context.ts +0 -567
- package/src/trace-helpers.new.test.ts +0 -278
- package/src/trace-helpers.test.ts +0 -290
- package/src/trace-helpers.ts +0 -710
- package/src/trace-hybrid.test.ts +0 -42
- package/src/trace-hybrid.ts +0 -37
- package/src/tracer-provider.test.ts +0 -183
- package/src/tracer-provider.ts +0 -266
- package/src/track.test.ts +0 -154
- package/src/track.ts +0 -216
- package/src/validate.test.ts +0 -287
- package/src/validate.ts +0 -307
- package/src/validation-attributes.ts +0 -43
- package/src/validation.test.ts +0 -330
- package/src/validation.ts +0 -246
- package/src/variable-name-inference.test.ts +0 -178
- package/src/variable-name-inference.ts +0 -242
- package/src/webhook.test.ts +0 -649
- package/src/webhook.ts +0 -637
- package/src/workflow-distributed.test.ts +0 -786
- package/src/workflow-distributed.ts +0 -916
- package/src/workflow.async-safety.integration.test.ts +0 -345
- package/src/workflow.test.ts +0 -647
- package/src/workflow.ts +0 -810
- package/src/yaml-config.test.ts +0 -337
- package/src/yaml-config.ts +0 -342
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow Async Safety Tests
|
|
3
|
-
*
|
|
4
|
-
* These tests verify that concurrent workflows are properly isolated
|
|
5
|
-
* using AsyncLocalStorage. Previously, a module-level variable was used
|
|
6
|
-
* which caused race conditions when multiple workflows ran concurrently.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
10
|
-
import {
|
|
11
|
-
traceWorkflow,
|
|
12
|
-
traceStep,
|
|
13
|
-
getCurrentWorkflowContext,
|
|
14
|
-
isInWorkflow,
|
|
15
|
-
} from './workflow';
|
|
16
|
-
import { init } from './init';
|
|
17
|
-
import { shutdown } from './shutdown';
|
|
18
|
-
import { resetConfig, getConfig } from './config';
|
|
19
|
-
import { InMemorySpanExporter } from './exporters';
|
|
20
|
-
import { SimpleSpanProcessor } from './processors';
|
|
21
|
-
|
|
22
|
-
describe('Workflow Async Safety', () => {
|
|
23
|
-
let exporter: InMemorySpanExporter;
|
|
24
|
-
|
|
25
|
-
beforeEach(() => {
|
|
26
|
-
// Reset config to ensure fresh tracer after SDK setup
|
|
27
|
-
resetConfig();
|
|
28
|
-
exporter = new InMemorySpanExporter();
|
|
29
|
-
init({
|
|
30
|
-
service: 'test-workflow-async-safety',
|
|
31
|
-
spanProcessors: [new SimpleSpanProcessor(exporter)],
|
|
32
|
-
});
|
|
33
|
-
// Reset again to pick up the newly configured tracer provider
|
|
34
|
-
resetConfig();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
afterEach(async () => {
|
|
38
|
-
await shutdown();
|
|
39
|
-
exporter.reset();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should isolate concurrent workflows', async () => {
|
|
43
|
-
const results: string[] = [];
|
|
44
|
-
|
|
45
|
-
// Debug: check config state
|
|
46
|
-
console.log(
|
|
47
|
-
'Config tracer constructor:',
|
|
48
|
-
getConfig().tracer?.constructor?.name,
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
const workflow1 = traceWorkflow({
|
|
52
|
-
name: 'Workflow1',
|
|
53
|
-
workflowId: 'wf-1',
|
|
54
|
-
})((ctx) => async () => {
|
|
55
|
-
console.log('workflow1 factory called, ctx:', ctx?.getWorkflowId?.());
|
|
56
|
-
// Record initial ID
|
|
57
|
-
results.push(`w1-start: ${ctx.getWorkflowId()}`);
|
|
58
|
-
|
|
59
|
-
// Simulate async work with delay
|
|
60
|
-
await sleep(20);
|
|
61
|
-
|
|
62
|
-
// Record ID after delay (should still be the same)
|
|
63
|
-
results.push(`w1-end: ${ctx.getWorkflowId()}`);
|
|
64
|
-
|
|
65
|
-
return ctx.getWorkflowId();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const workflow2 = traceWorkflow({
|
|
69
|
-
name: 'Workflow2',
|
|
70
|
-
workflowId: 'wf-2',
|
|
71
|
-
})((ctx) => async () => {
|
|
72
|
-
// Record initial ID
|
|
73
|
-
results.push(`w2-start: ${ctx.getWorkflowId()}`);
|
|
74
|
-
|
|
75
|
-
// Simulate async work with delay
|
|
76
|
-
await sleep(10);
|
|
77
|
-
|
|
78
|
-
// Record ID after delay (should still be the same)
|
|
79
|
-
results.push(`w2-end: ${ctx.getWorkflowId()}`);
|
|
80
|
-
|
|
81
|
-
return ctx.getWorkflowId();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
// Run workflows concurrently
|
|
85
|
-
const [r1, r2] = await Promise.all([workflow1(), workflow2()]);
|
|
86
|
-
|
|
87
|
-
// Verify return values are correct
|
|
88
|
-
expect(r1).toBe('wf-1');
|
|
89
|
-
expect(r2).toBe('wf-2');
|
|
90
|
-
|
|
91
|
-
// Verify each workflow maintained its own ID throughout execution
|
|
92
|
-
expect(results).toContain('w1-start: wf-1');
|
|
93
|
-
expect(results).toContain('w1-end: wf-1');
|
|
94
|
-
expect(results).toContain('w2-start: wf-2');
|
|
95
|
-
expect(results).toContain('w2-end: wf-2');
|
|
96
|
-
|
|
97
|
-
// Verify no cross-contamination (w1 should never see wf-2 and vice versa)
|
|
98
|
-
expect(
|
|
99
|
-
results
|
|
100
|
-
.filter((r) => r.startsWith('w1-'))
|
|
101
|
-
.every((r) => r.includes('wf-1')),
|
|
102
|
-
).toBe(true);
|
|
103
|
-
expect(
|
|
104
|
-
results
|
|
105
|
-
.filter((r) => r.startsWith('w2-'))
|
|
106
|
-
.every((r) => r.includes('wf-2')),
|
|
107
|
-
).toBe(true);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should isolate workflow contexts with getCurrentWorkflowContext()', async () => {
|
|
111
|
-
const contextIds: string[] = [];
|
|
112
|
-
|
|
113
|
-
const workflow1 = traceWorkflow({
|
|
114
|
-
name: 'Workflow1',
|
|
115
|
-
workflowId: 'wf-ctx-1',
|
|
116
|
-
})(() => async () => {
|
|
117
|
-
await sleep(10);
|
|
118
|
-
const ctx = getCurrentWorkflowContext();
|
|
119
|
-
contextIds.push(`w1: ${ctx?.getWorkflowId() ?? 'null'}`);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const workflow2 = traceWorkflow({
|
|
123
|
-
name: 'Workflow2',
|
|
124
|
-
workflowId: 'wf-ctx-2',
|
|
125
|
-
})(() => async () => {
|
|
126
|
-
const ctx = getCurrentWorkflowContext();
|
|
127
|
-
contextIds.push(`w2: ${ctx?.getWorkflowId() ?? 'null'}`);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
await Promise.all([workflow1(), workflow2()]);
|
|
131
|
-
|
|
132
|
-
expect(contextIds).toContain('w1: wf-ctx-1');
|
|
133
|
-
expect(contextIds).toContain('w2: wf-ctx-2');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should isolate isInWorkflow() across concurrent workflows', async () => {
|
|
137
|
-
let outsideWorkflow = true;
|
|
138
|
-
const insideWorkflow: boolean[] = [];
|
|
139
|
-
|
|
140
|
-
// Check outside
|
|
141
|
-
outsideWorkflow = isInWorkflow();
|
|
142
|
-
|
|
143
|
-
const workflow1 = traceWorkflow({
|
|
144
|
-
name: 'Workflow1',
|
|
145
|
-
workflowId: 'wf-check-1',
|
|
146
|
-
})(() => async () => {
|
|
147
|
-
await sleep(10);
|
|
148
|
-
insideWorkflow.push(isInWorkflow());
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
const workflow2 = traceWorkflow({
|
|
152
|
-
name: 'Workflow2',
|
|
153
|
-
workflowId: 'wf-check-2',
|
|
154
|
-
})(() => async () => {
|
|
155
|
-
insideWorkflow.push(isInWorkflow());
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
await Promise.all([workflow1(), workflow2()]);
|
|
159
|
-
|
|
160
|
-
// Outside should be false
|
|
161
|
-
expect(outsideWorkflow).toBe(false);
|
|
162
|
-
|
|
163
|
-
// Both inside checks should be true
|
|
164
|
-
expect(insideWorkflow).toEqual([true, true]);
|
|
165
|
-
|
|
166
|
-
// After workflows complete, should be false again
|
|
167
|
-
expect(isInWorkflow()).toBe(false);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('should register compensations with correct workflow', async () => {
|
|
171
|
-
const compensations: string[] = [];
|
|
172
|
-
|
|
173
|
-
const workflow1 = traceWorkflow({
|
|
174
|
-
name: 'Workflow1',
|
|
175
|
-
workflowId: 'wf-comp-1',
|
|
176
|
-
})((ctx) => async () => {
|
|
177
|
-
ctx.registerCompensation('step1', () => {
|
|
178
|
-
compensations.push('wf-1:step1');
|
|
179
|
-
});
|
|
180
|
-
ctx.completeStep('step1');
|
|
181
|
-
await sleep(10);
|
|
182
|
-
throw new Error('trigger compensation 1');
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const workflow2 = traceWorkflow({
|
|
186
|
-
name: 'Workflow2',
|
|
187
|
-
workflowId: 'wf-comp-2',
|
|
188
|
-
})((ctx) => async () => {
|
|
189
|
-
ctx.registerCompensation('step1', () => {
|
|
190
|
-
compensations.push('wf-2:step1');
|
|
191
|
-
});
|
|
192
|
-
ctx.completeStep('step1');
|
|
193
|
-
throw new Error('trigger compensation 2');
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
await Promise.allSettled([workflow1(), workflow2()]);
|
|
197
|
-
|
|
198
|
-
// Each workflow should have triggered its own compensation
|
|
199
|
-
expect(compensations.filter((c) => c.startsWith('wf-1'))).toHaveLength(1);
|
|
200
|
-
expect(compensations.filter((c) => c.startsWith('wf-2'))).toHaveLength(1);
|
|
201
|
-
expect(compensations).toContain('wf-1:step1');
|
|
202
|
-
expect(compensations).toContain('wf-2:step1');
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('should isolate traceStep() within concurrent workflows', async () => {
|
|
206
|
-
const stepWorkflows: string[] = [];
|
|
207
|
-
|
|
208
|
-
const workflow1 = traceWorkflow({
|
|
209
|
-
name: 'Workflow1',
|
|
210
|
-
workflowId: 'wf-step-1',
|
|
211
|
-
})(() => async () => {
|
|
212
|
-
await sleep(15);
|
|
213
|
-
|
|
214
|
-
const step = traceStep({
|
|
215
|
-
name: 'MyStep',
|
|
216
|
-
})(async () => {
|
|
217
|
-
const ctx = getCurrentWorkflowContext();
|
|
218
|
-
stepWorkflows.push(`w1-step: ${ctx?.getWorkflowId() ?? 'null'}`);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
await step();
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const workflow2 = traceWorkflow({
|
|
225
|
-
name: 'Workflow2',
|
|
226
|
-
workflowId: 'wf-step-2',
|
|
227
|
-
})(() => async () => {
|
|
228
|
-
await sleep(5);
|
|
229
|
-
|
|
230
|
-
const step = traceStep({
|
|
231
|
-
name: 'MyStep',
|
|
232
|
-
})(async () => {
|
|
233
|
-
const ctx = getCurrentWorkflowContext();
|
|
234
|
-
stepWorkflows.push(`w2-step: ${ctx?.getWorkflowId() ?? 'null'}`);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
await step();
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
await Promise.all([workflow1(), workflow2()]);
|
|
241
|
-
|
|
242
|
-
// Each step should see its parent workflow's ID
|
|
243
|
-
expect(stepWorkflows).toContain('w1-step: wf-step-1');
|
|
244
|
-
expect(stepWorkflows).toContain('w2-step: wf-step-2');
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('should handle many concurrent workflows', async () => {
|
|
248
|
-
const NUM_WORKFLOWS = 20;
|
|
249
|
-
const results = new Map<string, string[]>();
|
|
250
|
-
|
|
251
|
-
const workflows = Array.from({ length: NUM_WORKFLOWS }, (_, i) => {
|
|
252
|
-
const id = `wf-${i}`;
|
|
253
|
-
results.set(id, []);
|
|
254
|
-
|
|
255
|
-
return traceWorkflow({
|
|
256
|
-
name: `Workflow${i}`,
|
|
257
|
-
workflowId: id,
|
|
258
|
-
})((ctx) => async () => {
|
|
259
|
-
const myResults = results.get(id)!;
|
|
260
|
-
|
|
261
|
-
myResults.push(`start: ${ctx.getWorkflowId()}`);
|
|
262
|
-
|
|
263
|
-
// Random delay to increase chance of interleaving
|
|
264
|
-
await sleep(Math.random() * 20);
|
|
265
|
-
|
|
266
|
-
myResults.push(`middle: ${ctx.getWorkflowId()}`);
|
|
267
|
-
|
|
268
|
-
await sleep(Math.random() * 10);
|
|
269
|
-
|
|
270
|
-
myResults.push(`end: ${ctx.getWorkflowId()}`);
|
|
271
|
-
|
|
272
|
-
return ctx.getWorkflowId();
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
const returned = await Promise.all(workflows.map((w) => w()));
|
|
277
|
-
|
|
278
|
-
// Verify all workflows returned correct IDs
|
|
279
|
-
for (let i = 0; i < NUM_WORKFLOWS; i++) {
|
|
280
|
-
expect(returned[i]).toBe(`wf-${i}`);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Verify each workflow maintained its own context
|
|
284
|
-
for (let i = 0; i < NUM_WORKFLOWS; i++) {
|
|
285
|
-
const id = `wf-${i}`;
|
|
286
|
-
const myResults = results.get(id)!;
|
|
287
|
-
|
|
288
|
-
expect(myResults).toHaveLength(3);
|
|
289
|
-
expect(myResults.every((r) => r.includes(id))).toBe(true);
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
it('should support nested workflows with isolated contexts', async () => {
|
|
294
|
-
const nestedResults: string[] = [];
|
|
295
|
-
|
|
296
|
-
const outerWorkflow = traceWorkflow({
|
|
297
|
-
name: 'OuterWorkflow',
|
|
298
|
-
workflowId: 'wf-outer',
|
|
299
|
-
})((ctx) => async () => {
|
|
300
|
-
nestedResults.push(`outer-start: ${ctx.getWorkflowId()}`);
|
|
301
|
-
|
|
302
|
-
// Inner workflow should have its own context
|
|
303
|
-
const innerWorkflow = traceWorkflow({
|
|
304
|
-
name: 'InnerWorkflow',
|
|
305
|
-
workflowId: 'wf-inner',
|
|
306
|
-
})((innerCtx) => async () => {
|
|
307
|
-
nestedResults.push(`inner: ${innerCtx.getWorkflowId()}`);
|
|
308
|
-
|
|
309
|
-
// getCurrentWorkflowContext should return inner context
|
|
310
|
-
const current = getCurrentWorkflowContext();
|
|
311
|
-
nestedResults.push(
|
|
312
|
-
`inner-current: ${current?.getWorkflowId() ?? 'null'}`,
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
return innerCtx.getWorkflowId();
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
await innerWorkflow();
|
|
319
|
-
|
|
320
|
-
// After inner completes, outer should still have its context
|
|
321
|
-
nestedResults.push(`outer-end: ${ctx.getWorkflowId()}`);
|
|
322
|
-
|
|
323
|
-
// getCurrentWorkflowContext should return outer context again
|
|
324
|
-
const current = getCurrentWorkflowContext();
|
|
325
|
-
nestedResults.push(
|
|
326
|
-
`outer-current: ${current?.getWorkflowId() ?? 'null'}`,
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
return ctx.getWorkflowId();
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
const result = await outerWorkflow();
|
|
333
|
-
|
|
334
|
-
expect(result).toBe('wf-outer');
|
|
335
|
-
expect(nestedResults).toContain('outer-start: wf-outer');
|
|
336
|
-
expect(nestedResults).toContain('inner: wf-inner');
|
|
337
|
-
expect(nestedResults).toContain('inner-current: wf-inner');
|
|
338
|
-
expect(nestedResults).toContain('outer-end: wf-outer');
|
|
339
|
-
expect(nestedResults).toContain('outer-current: wf-outer');
|
|
340
|
-
});
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
function sleep(ms: number): Promise<void> {
|
|
344
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
345
|
-
}
|