@iworkflow/temporal 0.6.1 → 0.7.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/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { Context } from "@temporalio/activity";
4
4
  import { NativeConnection, Worker } from "@temporalio/worker";
5
5
  import {
6
6
  stepScope,
7
+ checkLimits,
7
8
  checkPriority,
8
9
  DEFAULT_PRIORITY,
9
10
  exitSignal,
@@ -167,8 +168,14 @@ function temporalRuntime(workflowsPath, opts = {}) {
167
168
  async start(def) {
168
169
  if (starting)
169
170
  throw new Error("воркер уже запущен");
170
- starting = true;
171
171
  exit.arm();
172
+ try {
173
+ checkLimits(def);
174
+ } catch (e) {
175
+ exit.reject(e);
176
+ throw e;
177
+ }
178
+ starting = true;
172
179
  stopping = false;
173
180
  let c;
174
181
  try {
@@ -183,7 +190,15 @@ function temporalRuntime(workflowsPath, opts = {}) {
183
190
  const activities = temporalActivities(def.activities);
184
191
  const base = { connection: c, namespace: namespace(opts), ...opts.plugins ? { plugins: opts.plugins } : {} };
185
192
  const code = opts.workflowBundlePath ? { workflowBundle: { codePath: opts.workflowBundlePath } } : { workflowsPath };
186
- workers = [await Worker.create({ ...base, taskQueue: def.app, ...code, activities })];
193
+ workers = [
194
+ await Worker.create({
195
+ ...base,
196
+ taskQueue: def.app,
197
+ ...code,
198
+ activities,
199
+ ...def.maxConcurrentSteps ? { maxConcurrentActivityTaskExecutions: def.maxConcurrentSteps } : {}
200
+ })
201
+ ];
187
202
  for (const [pool, limit] of Object.entries(def.pools ?? {}))
188
203
  workers.push(await Worker.create({
189
204
  ...base,
@@ -267,7 +282,12 @@ async function temporalClient(opts = {}) {
267
282
  return {
268
283
  async start(target, args, o) {
269
284
  await ready();
270
- const h = await client.workflow.start(target.flow, { ...startOptions(target, args, o), workflowIdConflictPolicy: "USE_EXISTING" });
285
+ const h = await client.workflow.start(target.flow, {
286
+ ...startOptions(target, args, o),
287
+ ...o.onExisting === "reject" ? { workflowIdConflictPolicy: "FAIL", workflowIdReusePolicy: "REJECT_DUPLICATE" } : { workflowIdConflictPolicy: "USE_EXISTING" }
288
+ }).catch((e) => {
289
+ throw fromTemporal(e);
290
+ });
271
291
  return wrap(h, ready);
272
292
  },
273
293
  async signalWithStart(target, args, o, topic, value) {
package/dist/workflow.js CHANGED
@@ -126,8 +126,10 @@ function temporalFlow(flow, patches = []) {
126
126
  step: (name, stepArgs, opts) => activitiesWith(opts)[name](...stepArgs).catch(rethrow),
127
127
  child: (target, childArgs, opts) => executeChild(target.flow, childOptions(target.app, childArgs, opts)).catch(rethrow),
128
128
  async startChild(target, childArgs, opts) {
129
+ const { reuseClosedId, ...rest } = opts;
129
130
  const h = await startChild(target.flow, {
130
- ...childOptions(target.app, childArgs, { ...opts, onExisting: "reject" }),
131
+ ...childOptions(target.app, childArgs, { ...rest, onExisting: "reject" }),
132
+ ...reuseClosedId ? { workflowIdReusePolicy: "ALLOW_DUPLICATE" } : {},
131
133
  parentClosePolicy: ParentClosePolicy.ABANDON
132
134
  }).catch(rethrow);
133
135
  return { id: opts.id, result: () => h.result().catch(rethrow) };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iworkflow/temporal",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Temporal adapter for @iworkflow/core",
5
5
  "keywords": [
6
6
  "workflow",
@@ -41,7 +41,7 @@
41
41
  "prepack": "bun run build"
42
42
  },
43
43
  "dependencies": {
44
- "@iworkflow/core": "^0.6.1"
44
+ "@iworkflow/core": "^0.7.0"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@temporalio/activity": "^1.24.0",
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import { NativeConnection, Worker } from "@temporalio/worker";
5
5
  import {
6
6
  stepScope,
7
7
  type StepRuntime,
8
+ checkLimits,
8
9
  checkPriority,
9
10
  DEFAULT_PRIORITY,
10
11
  exitSignal,
@@ -19,7 +20,7 @@ import {
19
20
  type StartOptions,
20
21
  } from "@iworkflow/core";
21
22
  import { address, connectOptions, namespace, renewApiKey, type TemporalOptions } from "./connection";
22
- import { cause, toTemporal } from "./failure";
23
+ import { cause, fromTemporal, toTemporal } from "./failure";
23
24
  import { alsScope } from "./scope";
24
25
 
25
26
  export type { TemporalOptions };
@@ -120,8 +121,14 @@ export function temporalRuntime(
120
121
  return {
121
122
  async start(def: AppDefinition) {
122
123
  if (starting) throw new Error("воркер уже запущен");
123
- starting = true;
124
124
  exit.arm();
125
+ try {
126
+ checkLimits(def);
127
+ } catch (e) {
128
+ exit.reject(e);
129
+ throw e;
130
+ }
131
+ starting = true;
125
132
  stopping = false;
126
133
  let c: NativeConnection;
127
134
  try {
@@ -137,7 +144,15 @@ export function temporalRuntime(
137
144
  const activities = temporalActivities(def.activities);
138
145
  const base = { connection: c, namespace: namespace(opts), ...(opts.plugins ? { plugins: opts.plugins } : {}) };
139
146
  const code = opts.workflowBundlePath ? { workflowBundle: { codePath: opts.workflowBundlePath } } : { workflowsPath };
140
- workers = [await Worker.create({ ...base, taskQueue: def.app, ...code, activities })];
147
+ workers = [
148
+ await Worker.create({
149
+ ...base,
150
+ taskQueue: def.app,
151
+ ...code,
152
+ activities,
153
+ ...(def.maxConcurrentSteps ? { maxConcurrentActivityTaskExecutions: def.maxConcurrentSteps } : {}),
154
+ }),
155
+ ];
141
156
  // Пул — своя очередь с пределом одновременных шагов в этом процессе.
142
157
  for (const [pool, limit] of Object.entries(def.pools ?? {}))
143
158
  workers.push(
@@ -232,7 +247,16 @@ export async function temporalClient(opts: TemporalOptions & { lazy?: boolean }
232
247
  return {
233
248
  async start(target, args, o) {
234
249
  await ready();
235
- const h = await client.workflow.start(target.flow, { ...startOptions(target, args, o), workflowIdConflictPolicy: "USE_EXISTING" });
250
+ const h = await client.workflow
251
+ .start(target.flow, {
252
+ ...startOptions(target, args, o),
253
+ ...(o.onExisting === "reject"
254
+ ? { workflowIdConflictPolicy: "FAIL" as const, workflowIdReusePolicy: "REJECT_DUPLICATE" as const }
255
+ : { workflowIdConflictPolicy: "USE_EXISTING" as const }),
256
+ })
257
+ .catch((e) => {
258
+ throw fromTemporal(e);
259
+ });
236
260
  return wrap(h, ready);
237
261
  },
238
262
  async signalWithStart(target, args, o, topic, value) {
package/src/workflow.ts CHANGED
@@ -94,9 +94,11 @@ export function temporalFlow(flow: Flow, patches: string[] = []) {
94
94
  child: (target, childArgs, opts) =>
95
95
  executeChild(target.flow, childOptions(target.app, childArgs, opts)).catch(rethrow) as Promise<never>,
96
96
  async startChild(target, childArgs, opts) {
97
- // REJECT_DUPLICATE: завершённый id тоже занят — как у DBOS, где id не переиспользуется.
97
+ // REJECT_DUPLICATE: завершённый id тоже занят, как у DBOS; reuseClosedId — ALLOW_DUPLICATE, новый запуск.
98
+ const { reuseClosedId, ...rest } = opts;
98
99
  const h = await startChild(target.flow, {
99
- ...childOptions(target.app, childArgs, { ...opts, onExisting: "reject" }),
100
+ ...childOptions(target.app, childArgs, { ...rest, onExisting: "reject" }),
101
+ ...(reuseClosedId ? { workflowIdReusePolicy: "ALLOW_DUPLICATE" as const } : {}),
100
102
  parentClosePolicy: ParentClosePolicy.ABANDON,
101
103
  }).catch(rethrow);
102
104
  return { id: opts.id, result: () => h.result().catch(rethrow) as Promise<never> };