mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2026-02-06 16:18:45 -06:00
Feat: ts direct child spawning (#1872)
* feat: context vars * docs: gen * rm test * fix: schedule timeout handling * release: 1.8.0 * helpful error
This commit is contained in:
@@ -27,7 +27,7 @@ export const parent = hatchet.task({
|
||||
const promises = [];
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
promises.push(ctx.runChild(child, { N: i }));
|
||||
promises.push(child.run({ N: i }));
|
||||
}
|
||||
|
||||
const childRes = await Promise.all(promises);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { hatchet } from '../hatchet-client';
|
||||
import { simple } from './workflow';
|
||||
import { parent } from './workflow-with-child';
|
||||
|
||||
async function main() {
|
||||
// > Running a Task
|
||||
const res = await simple.run(
|
||||
const res = await parent.run(
|
||||
{
|
||||
Message: 'HeLlO WoRlD',
|
||||
},
|
||||
@@ -34,11 +35,11 @@ export async function extra() {
|
||||
console.log(results[1].TransformedMessage);
|
||||
|
||||
// > Spawning Tasks from within a Task
|
||||
const parent = hatchet.task({
|
||||
const parentTask = hatchet.task({
|
||||
name: 'parent',
|
||||
fn: async (input, ctx) => {
|
||||
// Simply call ctx.runChild with the task you want to run
|
||||
const child = await ctx.runChild(simple, {
|
||||
// Simply the task and it will be spawned from the parent task
|
||||
const child = await simple.run({
|
||||
Message: 'HeLlO WoRlD',
|
||||
});
|
||||
|
||||
@@ -50,5 +51,9 @@ export async function extra() {
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
main()
|
||||
.catch(console.error)
|
||||
.finally(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ export const sticky = hatchet.task({
|
||||
sticky: StickyStrategy.SOFT,
|
||||
fn: async (_, ctx) => {
|
||||
// specify a child workflow to run on the same worker
|
||||
const result = await ctx.runChild(
|
||||
child,
|
||||
const result = await child.run(
|
||||
{
|
||||
N: 1,
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Snippet } from '@/next/lib/docs/generated/snips/types';
|
||||
const snippet: Snippet = {
|
||||
language: 'typescript ',
|
||||
content:
|
||||
"// > Declaring a Child\nimport { hatchet } from '../hatchet-client';\n\ntype ChildInput = {\n N: number;\n};\n\nexport const child = hatchet.task({\n name: 'child',\n fn: (input: ChildInput) => {\n return {\n Value: input.N,\n };\n },\n});\n\n// > Declaring a Parent\n\ntype ParentInput = {\n N: number;\n};\n\nexport const parent = hatchet.task({\n name: 'parent',\n fn: async (input: ParentInput, ctx) => {\n const n = input.N;\n const promises = [];\n\n for (let i = 0; i < n; i++) {\n promises.push(ctx.runChild(child, { N: i }));\n }\n\n const childRes = await Promise.all(promises);\n const sum = childRes.reduce((acc, curr) => acc + curr.Value, 0);\n\n return {\n Result: sum,\n };\n },\n});\n",
|
||||
"// > Declaring a Child\nimport { hatchet } from '../hatchet-client';\n\ntype ChildInput = {\n N: number;\n};\n\nexport const child = hatchet.task({\n name: 'child',\n fn: (input: ChildInput) => {\n return {\n Value: input.N,\n };\n },\n});\n\n// > Declaring a Parent\n\ntype ParentInput = {\n N: number;\n};\n\nexport const parent = hatchet.task({\n name: 'parent',\n fn: async (input: ParentInput, ctx) => {\n const n = input.N;\n const promises = [];\n\n for (let i = 0; i < n; i++) {\n promises.push(child.run({ N: i }));\n }\n\n const childRes = await Promise.all(promises);\n const sum = childRes.reduce((acc, curr) => acc + curr.Value, 0);\n\n return {\n Result: sum,\n };\n },\n});\n",
|
||||
source: 'out/typescript/child_workflows/workflow.ts',
|
||||
blocks: {
|
||||
declaring_a_child: {
|
||||
|
||||
@@ -3,20 +3,20 @@ import { Snippet } from '@/next/lib/docs/generated/snips/types';
|
||||
const snippet: Snippet = {
|
||||
language: 'typescript ',
|
||||
content:
|
||||
"import { hatchet } from '../hatchet-client';\nimport { simple } from './workflow';\n\nasync function main() {\n // > Running a Task\n const res = await simple.run(\n {\n Message: 'HeLlO WoRlD',\n },\n {\n additionalMetadata: {\n test: 'test',\n },\n }\n );\n\n // 👀 Access the results of the Task\n console.log(res.TransformedMessage);\n}\n\nexport async function extra() {\n // > Running Multiple Tasks\n const res1 = simple.run({\n Message: 'HeLlO WoRlD',\n });\n\n const res2 = simple.run({\n Message: 'Hello MoOn',\n });\n\n const results = await Promise.all([res1, res2]);\n\n console.log(results[0].TransformedMessage);\n console.log(results[1].TransformedMessage);\n\n // > Spawning Tasks from within a Task\n const parent = hatchet.task({\n name: 'parent',\n fn: async (input, ctx) => {\n // Simply call ctx.runChild with the task you want to run\n const child = await ctx.runChild(simple, {\n Message: 'HeLlO WoRlD',\n });\n\n return {\n result: child.TransformedMessage,\n };\n },\n });\n}\n\nif (require.main === module) {\n main();\n}\n",
|
||||
"import { hatchet } from '../hatchet-client';\nimport { simple } from './workflow';\nimport { parent } from './workflow-with-child';\n\nasync function main() {\n // > Running a Task\n const res = await parent.run(\n {\n Message: 'HeLlO WoRlD',\n },\n {\n additionalMetadata: {\n test: 'test',\n },\n }\n );\n\n // 👀 Access the results of the Task\n console.log(res.TransformedMessage);\n}\n\nexport async function extra() {\n // > Running Multiple Tasks\n const res1 = simple.run({\n Message: 'HeLlO WoRlD',\n });\n\n const res2 = simple.run({\n Message: 'Hello MoOn',\n });\n\n const results = await Promise.all([res1, res2]);\n\n console.log(results[0].TransformedMessage);\n console.log(results[1].TransformedMessage);\n\n // > Spawning Tasks from within a Task\n const parentTask = hatchet.task({\n name: 'parent',\n fn: async (input, ctx) => {\n // Simply the task and it will be spawned from the parent task\n const child = await simple.run({\n Message: 'HeLlO WoRlD',\n });\n\n return {\n result: child.TransformedMessage,\n };\n },\n });\n}\n\nif (require.main === module) {\n main()\n .catch(console.error)\n .finally(() => {\n process.exit(0);\n });\n}\n",
|
||||
source: 'out/typescript/simple/run.ts',
|
||||
blocks: {
|
||||
running_a_task: {
|
||||
start: 6,
|
||||
stop: 18,
|
||||
start: 7,
|
||||
stop: 19,
|
||||
},
|
||||
running_multiple_tasks: {
|
||||
start: 23,
|
||||
stop: 34,
|
||||
start: 24,
|
||||
stop: 35,
|
||||
},
|
||||
spawning_tasks_from_within_a_task: {
|
||||
start: 37,
|
||||
stop: 49,
|
||||
start: 38,
|
||||
stop: 50,
|
||||
},
|
||||
},
|
||||
highlights: {},
|
||||
|
||||
@@ -3,12 +3,12 @@ import { Snippet } from '@/next/lib/docs/generated/snips/types';
|
||||
const snippet: Snippet = {
|
||||
language: 'typescript ',
|
||||
content:
|
||||
"import { StickyStrategy } from '@hatchet-dev/typescript-sdk/protoc/workflows';\nimport { hatchet } from '../hatchet-client';\nimport { child } from '../child_workflows/workflow';\n\n// > Sticky Task\nexport const sticky = hatchet.task({\n name: 'sticky',\n retries: 3,\n sticky: StickyStrategy.SOFT,\n fn: async (_, ctx) => {\n // specify a child workflow to run on the same worker\n const result = await ctx.runChild(\n child,\n {\n N: 1,\n },\n { sticky: true }\n );\n\n return {\n result,\n };\n },\n});\n",
|
||||
"import { StickyStrategy } from '@hatchet-dev/typescript-sdk/protoc/workflows';\nimport { hatchet } from '../hatchet-client';\nimport { child } from '../child_workflows/workflow';\n\n// > Sticky Task\nexport const sticky = hatchet.task({\n name: 'sticky',\n retries: 3,\n sticky: StickyStrategy.SOFT,\n fn: async (_, ctx) => {\n // specify a child workflow to run on the same worker\n const result = await child.run(\n {\n N: 1,\n },\n { sticky: true }\n );\n\n return {\n result,\n };\n },\n});\n",
|
||||
source: 'out/typescript/sticky/workflow.ts',
|
||||
blocks: {
|
||||
sticky_task: {
|
||||
start: 6,
|
||||
stop: 24,
|
||||
stop: 23,
|
||||
},
|
||||
},
|
||||
highlights: {},
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Snippet } from '@/lib/generated/snips/types';
|
||||
|
||||
const snippet: Snippet = {
|
||||
"language": "typescript ",
|
||||
"content": "// > Declaring a Child\nimport { hatchet } from '../hatchet-client';\n\ntype ChildInput = {\n N: number;\n};\n\nexport const child = hatchet.task({\n name: 'child',\n fn: (input: ChildInput) => {\n return {\n Value: input.N,\n };\n },\n});\n\n// > Declaring a Parent\n\ntype ParentInput = {\n N: number;\n};\n\nexport const parent = hatchet.task({\n name: 'parent',\n fn: async (input: ParentInput, ctx) => {\n const n = input.N;\n const promises = [];\n\n for (let i = 0; i < n; i++) {\n promises.push(ctx.runChild(child, { N: i }));\n }\n\n const childRes = await Promise.all(promises);\n const sum = childRes.reduce((acc, curr) => acc + curr.Value, 0);\n\n return {\n Result: sum,\n };\n },\n});\n",
|
||||
"content": "// > Declaring a Child\nimport { hatchet } from '../hatchet-client';\n\ntype ChildInput = {\n N: number;\n};\n\nexport const child = hatchet.task({\n name: 'child',\n fn: (input: ChildInput) => {\n return {\n Value: input.N,\n };\n },\n});\n\n// > Declaring a Parent\n\ntype ParentInput = {\n N: number;\n};\n\nexport const parent = hatchet.task({\n name: 'parent',\n fn: async (input: ParentInput, ctx) => {\n const n = input.N;\n const promises = [];\n\n for (let i = 0; i < n; i++) {\n promises.push(child.run({ N: i }));\n }\n\n const childRes = await Promise.all(promises);\n const sum = childRes.reduce((acc, curr) => acc + curr.Value, 0);\n\n return {\n Result: sum,\n };\n },\n});\n",
|
||||
"source": "out/typescript/child_workflows/workflow.ts",
|
||||
"blocks": {
|
||||
"declaring_a_child": {
|
||||
|
||||
@@ -2,20 +2,20 @@ import { Snippet } from '@/lib/generated/snips/types';
|
||||
|
||||
const snippet: Snippet = {
|
||||
"language": "typescript ",
|
||||
"content": "import { hatchet } from '../hatchet-client';\nimport { simple } from './workflow';\n\nasync function main() {\n // > Running a Task\n const res = await simple.run(\n {\n Message: 'HeLlO WoRlD',\n },\n {\n additionalMetadata: {\n test: 'test',\n },\n }\n );\n\n // 👀 Access the results of the Task\n console.log(res.TransformedMessage);\n}\n\nexport async function extra() {\n // > Running Multiple Tasks\n const res1 = simple.run({\n Message: 'HeLlO WoRlD',\n });\n\n const res2 = simple.run({\n Message: 'Hello MoOn',\n });\n\n const results = await Promise.all([res1, res2]);\n\n console.log(results[0].TransformedMessage);\n console.log(results[1].TransformedMessage);\n\n // > Spawning Tasks from within a Task\n const parent = hatchet.task({\n name: 'parent',\n fn: async (input, ctx) => {\n // Simply call ctx.runChild with the task you want to run\n const child = await ctx.runChild(simple, {\n Message: 'HeLlO WoRlD',\n });\n\n return {\n result: child.TransformedMessage,\n };\n },\n });\n}\n\nif (require.main === module) {\n main();\n}\n",
|
||||
"content": "import { hatchet } from '../hatchet-client';\nimport { simple } from './workflow';\nimport { parent } from './workflow-with-child';\n\nasync function main() {\n // > Running a Task\n const res = await parent.run(\n {\n Message: 'HeLlO WoRlD',\n },\n {\n additionalMetadata: {\n test: 'test',\n },\n }\n );\n\n // 👀 Access the results of the Task\n console.log(res.TransformedMessage);\n}\n\nexport async function extra() {\n // > Running Multiple Tasks\n const res1 = simple.run({\n Message: 'HeLlO WoRlD',\n });\n\n const res2 = simple.run({\n Message: 'Hello MoOn',\n });\n\n const results = await Promise.all([res1, res2]);\n\n console.log(results[0].TransformedMessage);\n console.log(results[1].TransformedMessage);\n\n // > Spawning Tasks from within a Task\n const parentTask = hatchet.task({\n name: 'parent',\n fn: async (input, ctx) => {\n // Simply the task and it will be spawned from the parent task\n const child = await simple.run({\n Message: 'HeLlO WoRlD',\n });\n\n return {\n result: child.TransformedMessage,\n };\n },\n });\n}\n\nif (require.main === module) {\n main()\n .catch(console.error)\n .finally(() => {\n process.exit(0);\n });\n}\n",
|
||||
"source": "out/typescript/simple/run.ts",
|
||||
"blocks": {
|
||||
"running_a_task": {
|
||||
"start": 6,
|
||||
"stop": 18
|
||||
"start": 7,
|
||||
"stop": 19
|
||||
},
|
||||
"running_multiple_tasks": {
|
||||
"start": 23,
|
||||
"stop": 34
|
||||
"start": 24,
|
||||
"stop": 35
|
||||
},
|
||||
"spawning_tasks_from_within_a_task": {
|
||||
"start": 37,
|
||||
"stop": 49
|
||||
"start": 38,
|
||||
"stop": 50
|
||||
}
|
||||
},
|
||||
"highlights": {}
|
||||
|
||||
@@ -2,12 +2,12 @@ import { Snippet } from '@/lib/generated/snips/types';
|
||||
|
||||
const snippet: Snippet = {
|
||||
"language": "typescript ",
|
||||
"content": "import { StickyStrategy } from '@hatchet-dev/typescript-sdk/protoc/workflows';\nimport { hatchet } from '../hatchet-client';\nimport { child } from '../child_workflows/workflow';\n\n// > Sticky Task\nexport const sticky = hatchet.task({\n name: 'sticky',\n retries: 3,\n sticky: StickyStrategy.SOFT,\n fn: async (_, ctx) => {\n // specify a child workflow to run on the same worker\n const result = await ctx.runChild(\n child,\n {\n N: 1,\n },\n { sticky: true }\n );\n\n return {\n result,\n };\n },\n});\n",
|
||||
"content": "import { StickyStrategy } from '@hatchet-dev/typescript-sdk/protoc/workflows';\nimport { hatchet } from '../hatchet-client';\nimport { child } from '../child_workflows/workflow';\n\n// > Sticky Task\nexport const sticky = hatchet.task({\n name: 'sticky',\n retries: 3,\n sticky: StickyStrategy.SOFT,\n fn: async (_, ctx) => {\n // specify a child workflow to run on the same worker\n const result = await child.run(\n {\n N: 1,\n },\n { sticky: true }\n );\n\n return {\n result,\n };\n },\n});\n",
|
||||
"source": "out/typescript/sticky/workflow.ts",
|
||||
"blocks": {
|
||||
"sticky_task": {
|
||||
"start": 6,
|
||||
"stop": 24
|
||||
"stop": 23
|
||||
}
|
||||
},
|
||||
"highlights": {}
|
||||
|
||||
@@ -232,6 +232,7 @@ func (s *DispatcherImpl) taskEventsToWorkflowRunEvent(tenantId string, finalized
|
||||
case sqlcv1.V1TaskEventTypeFAILED:
|
||||
res.Error = &event.ErrorMessage
|
||||
case sqlcv1.V1TaskEventTypeCANCELLED:
|
||||
//FIXME: this should be more specific for schedule timeouts
|
||||
res.Error = &event.ErrorMessage
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@hatchet-dev/typescript-sdk",
|
||||
"version": "1.7.1",
|
||||
"version": "1.8.0",
|
||||
"description": "Background task orchestration & visibility for developers",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
|
||||
@@ -105,8 +105,13 @@ export default class WorkflowRunRef<T> {
|
||||
(async () => {
|
||||
for await (const event of streamable.stream()) {
|
||||
if (event.eventType === WorkflowRunEventType.WORKFLOW_RUN_EVENT_TYPE_FINISHED) {
|
||||
if (event.results.some((r) => !!r.error)) {
|
||||
reject(event.results);
|
||||
if (event.results.some((r) => r.error !== undefined)) {
|
||||
// HACK: this might replace intentional empty errors but this is the more common case
|
||||
const errors = event.results.map((r) =>
|
||||
r.error !== '' ? r.error : 'task was cancelled'
|
||||
);
|
||||
|
||||
reject(errors);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import { WorkerLabels } from '@hatchet/clients/dispatcher/dispatcher-client';
|
||||
import { CreateStep, mapRateLimit, StepRunFunction } from '@hatchet/step';
|
||||
import { applyNamespace } from '@hatchet/util/apply-namespace';
|
||||
import { Context, DurableContext } from './context';
|
||||
import { parentRunContextManager } from '../../parent-run-context-vars';
|
||||
|
||||
export type ActionRegistry = Record<Action['actionId'], Function>;
|
||||
|
||||
@@ -467,6 +468,12 @@ export class V1Worker {
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
parentRunContextManager.setContext({
|
||||
parentId: action.workflowRunId,
|
||||
parentRunId: action.stepRunId,
|
||||
childIndex: 0,
|
||||
desiredWorkerId: this.workerId || '',
|
||||
});
|
||||
return step(context);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import { Duration } from './client/duration';
|
||||
import { MetricsClient } from './client/features/metrics';
|
||||
import { InputType, OutputType, UnknownInputType, JsonObject } from './types';
|
||||
import { Context, DurableContext } from './client/worker/context';
|
||||
import { parentRunContextManager } from './parent-run-context-vars';
|
||||
|
||||
const UNBOUND_ERR = new Error('workflow unbound to hatchet client, hint: use client.run instead');
|
||||
|
||||
@@ -53,6 +54,18 @@ export type RunOpts = {
|
||||
* values: Priority.LOW, Priority.MEDIUM, Priority.HIGH (1, 2, or 3 )
|
||||
*/
|
||||
priority?: Priority;
|
||||
|
||||
/**
|
||||
* (optional) if the task run should be run on the same worker.
|
||||
* only used if spawned from within a parent task.
|
||||
*/
|
||||
sticky?: boolean;
|
||||
|
||||
/**
|
||||
* (optional) the child key for the workflow run.
|
||||
* only used if spawned from within a parent task.
|
||||
*/
|
||||
childKey?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -289,6 +302,25 @@ export class BaseWorkflowDeclaration<
|
||||
throw UNBOUND_ERR;
|
||||
}
|
||||
|
||||
// set the parent run context
|
||||
const parentRunContext = parentRunContextManager.getContext();
|
||||
parentRunContextManager.incrementChildIndex(Array.isArray(input) ? input.length : 1);
|
||||
|
||||
if (!parentRunContext && (options?.childKey || options?.sticky)) {
|
||||
this.client.admin.logger.warn(
|
||||
'ignoring childKey or sticky because run is not being spawned from a parent task'
|
||||
);
|
||||
}
|
||||
|
||||
const runOpts = {
|
||||
...options,
|
||||
parentId: parentRunContext?.parentId,
|
||||
parentStepRunId: parentRunContext?.parentRunId,
|
||||
childIndex: parentRunContext?.childIndex,
|
||||
sticky: options?.sticky ? parentRunContext?.desiredWorkerId : undefined,
|
||||
childKey: options?.childKey,
|
||||
};
|
||||
|
||||
if (Array.isArray(input)) {
|
||||
let resp: WorkflowRunRef<O>[] = [];
|
||||
for (let i = 0; i < input.length; i += 500) {
|
||||
@@ -297,7 +329,10 @@ export class BaseWorkflowDeclaration<
|
||||
batch.map((inp) => ({
|
||||
workflowName: this.definition.name,
|
||||
input: inp,
|
||||
options,
|
||||
options: {
|
||||
...runOpts,
|
||||
childIndex: (runOpts.childIndex ?? 0) + i, // increment from initial child index state
|
||||
},
|
||||
}))
|
||||
);
|
||||
resp = resp.concat(batchResp);
|
||||
@@ -319,7 +354,7 @@ export class BaseWorkflowDeclaration<
|
||||
return res;
|
||||
}
|
||||
|
||||
const res = await this.client.admin.runWorkflow<I, O>(this.definition.name, input, options);
|
||||
const res = await this.client.admin.runWorkflow<I, O>(this.definition.name, input, runOpts);
|
||||
|
||||
if (_standaloneTaskName) {
|
||||
res._standaloneTaskName = _standaloneTaskName;
|
||||
|
||||
@@ -29,7 +29,7 @@ export const parent = hatchet.task({
|
||||
const promises = [];
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
promises.push(ctx.runChild(child, { N: i }));
|
||||
promises.push(child.run({ N: i }));
|
||||
}
|
||||
|
||||
const childRes = await Promise.all(promises);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/* eslint-disable no-console */
|
||||
import { hatchet } from '../hatchet-client';
|
||||
import { simple } from './workflow';
|
||||
import { parent } from './workflow-with-child';
|
||||
|
||||
async function main() {
|
||||
// > Running a Task
|
||||
const res = await simple.run(
|
||||
const res = await parent.run(
|
||||
{
|
||||
Message: 'HeLlO WoRlD',
|
||||
},
|
||||
@@ -37,11 +38,11 @@ export async function extra() {
|
||||
// !!
|
||||
|
||||
// > Spawning Tasks from within a Task
|
||||
const parent = hatchet.task({
|
||||
const parentTask = hatchet.task({
|
||||
name: 'parent',
|
||||
fn: async (input, ctx) => {
|
||||
// Simply call ctx.runChild with the task you want to run
|
||||
const child = await ctx.runChild(simple, {
|
||||
// Simply the task and it will be spawned from the parent task
|
||||
const child = await simple.run({
|
||||
Message: 'HeLlO WoRlD',
|
||||
});
|
||||
|
||||
@@ -54,5 +55,9 @@ export async function extra() {
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
main()
|
||||
.catch(console.error)
|
||||
.finally(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ export const sticky = hatchet.task({
|
||||
sticky: StickyStrategy.SOFT,
|
||||
fn: async (_, ctx) => {
|
||||
// specify a child workflow to run on the same worker
|
||||
const result = await ctx.runChild(
|
||||
child,
|
||||
const result = await child.run(
|
||||
{
|
||||
N: 1,
|
||||
},
|
||||
|
||||
46
sdks/typescript/src/v1/parent-run-context-vars.ts
Normal file
46
sdks/typescript/src/v1/parent-run-context-vars.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { AsyncLocalStorage } from 'async_hooks';
|
||||
|
||||
export interface ParentRunContext {
|
||||
parentId: string;
|
||||
parentRunId: string;
|
||||
desiredWorkerId: string;
|
||||
childIndex?: number;
|
||||
}
|
||||
|
||||
export class ParentRunContextManager {
|
||||
private storage: AsyncLocalStorage<ParentRunContext>;
|
||||
|
||||
constructor() {
|
||||
this.storage = new AsyncLocalStorage<ParentRunContext>();
|
||||
}
|
||||
|
||||
setContext(opts: ParentRunContext): void {
|
||||
this.storage.enterWith({
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
|
||||
setParentRunIdAndIncrementChildIndex(opts: ParentRunContext): void {
|
||||
const parentRunContext = this.getContext();
|
||||
if (parentRunContext) {
|
||||
parentRunContext.parentId = opts.parentId;
|
||||
parentRunContext.childIndex = (parentRunContext.childIndex ?? 0) + 1;
|
||||
this.setContext(parentRunContext);
|
||||
}
|
||||
}
|
||||
|
||||
incrementChildIndex(n: number): void {
|
||||
const parentRunContext = this.getContext();
|
||||
if (parentRunContext) {
|
||||
parentRunContext.childIndex = (parentRunContext.childIndex ?? 0) + n;
|
||||
this.setContext(parentRunContext);
|
||||
}
|
||||
}
|
||||
|
||||
getContext(): ParentRunContext | undefined {
|
||||
return this.storage.getStore();
|
||||
}
|
||||
}
|
||||
|
||||
// Export a default instance for backward compatibility and convenience
|
||||
export const parentRunContextManager = new ParentRunContextManager();
|
||||
@@ -47,6 +47,7 @@
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
] /* Specify type package names to be included without being referenced in a source file. */,
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
|
||||
Reference in New Issue
Block a user