@sixb/pipeline-worker 0.0.1

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 ADDED
@@ -0,0 +1,654 @@
1
+ // @bun
2
+ // src/worker.ts
3
+ import { reportRunFailure } from "@sixb/core/internal/error-reporting";
4
+ import { QueueWorker } from "@sixb/core/internal/workers";
5
+
6
+ // src/events.ts
7
+ var SOURCE = "SixbPipelineWorker";
8
+ async function emitPipelineRunStarted(events, run) {
9
+ await events?.emit({
10
+ events: [
11
+ {
12
+ type: "pipeline.run.started",
13
+ payload: {
14
+ pipelineId: run.pipelineId,
15
+ runId: run.id,
16
+ startedAt: run.startedAt.toISOString()
17
+ }
18
+ }
19
+ ]
20
+ }, { source: SOURCE });
21
+ }
22
+ async function emitPipelineRunStepStarted(events, step, context) {
23
+ await events?.emit({
24
+ events: [
25
+ {
26
+ type: "pipeline.run.step.started",
27
+ payload: {
28
+ pipelineId: step.pipelineId,
29
+ runId: step.pipelineRunId,
30
+ stepRunId: step.id,
31
+ stepId: step.stepId,
32
+ stepIndex: context.stepIndex,
33
+ totalSteps: context.totalSteps,
34
+ datasetId: step.datasetId,
35
+ startedAt: step.startedAt.toISOString()
36
+ }
37
+ }
38
+ ]
39
+ }, { source: SOURCE });
40
+ }
41
+ async function emitPipelineRunStepFinished(events, step, context) {
42
+ await events?.emit({
43
+ events: [
44
+ {
45
+ type: "pipeline.run.step.finished",
46
+ payload: {
47
+ pipelineId: step.pipelineId,
48
+ runId: step.pipelineRunId,
49
+ stepRunId: step.id,
50
+ stepId: step.stepId,
51
+ stepIndex: context.stepIndex,
52
+ totalSteps: context.totalSteps,
53
+ datasetId: step.datasetId,
54
+ status: requireTerminalStatus(step.status, `Pipeline step run '${step.id}'`),
55
+ finishedAt: requireFinishedAt(step.id, step.finishedAt).toISOString(),
56
+ ...step.output ? { versionId: step.output.versionId } : {},
57
+ ...step.rowsWritten !== undefined ? { rowsWritten: step.rowsWritten } : {},
58
+ ...step.error ? { error: step.error.message } : {}
59
+ }
60
+ }
61
+ ]
62
+ }, { source: SOURCE });
63
+ }
64
+ async function emitDatasetVersionCommitted(events, job, step) {
65
+ if (!step.versionCreated)
66
+ return;
67
+ await events?.emit({
68
+ events: [
69
+ {
70
+ type: "dataset.version.committed",
71
+ payload: {
72
+ datasetId: step.version.datasetId,
73
+ versionId: step.version.versionId,
74
+ createdAt: step.version.createdAt.toISOString(),
75
+ producer: {
76
+ kind: "pipeline",
77
+ id: job.pipelineId,
78
+ runId: job.id,
79
+ stepId: step.run.stepId
80
+ }
81
+ }
82
+ }
83
+ ]
84
+ }, { source: SOURCE });
85
+ }
86
+ async function emitPipelineRunFinished(events, job) {
87
+ await events?.emit({ events: [{ type: "pipeline.run.finished", payload: buildPipelineRunFinishedPayload(job) }] }, { source: SOURCE });
88
+ }
89
+ function buildPipelineRunFinishedPayload(job) {
90
+ return {
91
+ pipelineId: job.pipelineId,
92
+ runId: job.id,
93
+ status: job.status,
94
+ ...job.datasetId && job.versionId ? {
95
+ datasetId: job.datasetId,
96
+ versionId: job.versionId
97
+ } : {}
98
+ };
99
+ }
100
+ function requireFinishedAt(stepRunId, finishedAt) {
101
+ if (finishedAt) {
102
+ return finishedAt;
103
+ }
104
+ throw new Error(`[SixbPipelineWorker] Pipeline step run '${stepRunId}' has no finishedAt.`);
105
+ }
106
+ function requireTerminalStatus(status, context) {
107
+ if (status === "running") {
108
+ throw new Error(`[SixbPipelineWorker] ${context} is still running.`);
109
+ }
110
+ return status;
111
+ }
112
+
113
+ // src/run-pipeline-job.ts
114
+ import { resolveLogsRuntime } from "@sixb/core/internal/logging";
115
+
116
+ // src/errors.ts
117
+ class PipelineWorkerError extends Error {
118
+ name = "PipelineWorkerError";
119
+ }
120
+ function toPipelineRunFailure(error) {
121
+ if (error instanceof Error) {
122
+ return {
123
+ name: error.name,
124
+ message: error.message
125
+ };
126
+ }
127
+ return {
128
+ message: String(error)
129
+ };
130
+ }
131
+ function throwIfAborted(signal) {
132
+ if (signal.aborted) {
133
+ throw createAbortError();
134
+ }
135
+ }
136
+ function statusForFailure(signal, error) {
137
+ return signal.aborted || isAbortError(error) ? "cancelled" : "failed";
138
+ }
139
+ function requireFinishedAt2(runId, finishedAt) {
140
+ if (finishedAt) {
141
+ return finishedAt;
142
+ }
143
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Pipeline run '${runId}' finished without a finishedAt timestamp.`);
144
+ }
145
+ function createStepBookkeepingError(options) {
146
+ return new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${options.pipelineId}' step '${options.stepId}' committed dataset version '${options.version.versionId}', but failed to finalize step run '${options.runId}'. The dataset commit may already have succeeded and the step run record may need repair.`, { cause: options.cause });
147
+ }
148
+ function createPipelineBookkeepingError(options) {
149
+ return new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${options.pipelineId}' committed final dataset version '${options.version.versionId}', but failed to finalize pipeline run '${options.runId}'. The dataset commit may already have succeeded and the pipeline run record may need repair.`, { cause: options.cause });
150
+ }
151
+ function requirePipeline(pipeline, job) {
152
+ if (!pipeline) {
153
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Unknown pipeline '${job.pipelineId}'.`);
154
+ }
155
+ return pipeline;
156
+ }
157
+ function requireRegisteredDataset(options) {
158
+ if (options.dataset) {
159
+ return options.dataset;
160
+ }
161
+ const namedRole = options.role === "input" ? `input '${options.name ?? "unknown"}'` : "output";
162
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${options.pipelineId}' step '${options.stepId}' ${namedRole} references unknown dataset '${options.datasetId}'.`);
163
+ }
164
+ function createAbortError() {
165
+ const error = new Error("Worker runtime aborted.");
166
+ error.name = "AbortError";
167
+ return error;
168
+ }
169
+ function isAbortError(error) {
170
+ return error instanceof Error && error.name === "AbortError";
171
+ }
172
+
173
+ // src/step-inputs.ts
174
+ async function resolveStepInputs(input) {
175
+ const { runtime, pipeline, step } = input;
176
+ const resolved = [];
177
+ for (const [name, declaredDataset] of Object.entries(step.inputs)) {
178
+ const dataset = requireRegisteredDataset({
179
+ dataset: runtime.getDatasetById(declaredDataset.id),
180
+ pipelineId: pipeline.id,
181
+ stepId: step.id,
182
+ role: "input",
183
+ name,
184
+ datasetId: declaredDataset.id
185
+ });
186
+ const version = await runtime.lakeStorage.getLatestVersion(dataset.id);
187
+ if (!version) {
188
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${pipeline.id}' step '${step.id}' input '${name}' dataset '${dataset.id}' has no committed version.`);
189
+ }
190
+ resolved.push({
191
+ name,
192
+ dataset,
193
+ version,
194
+ ref: {
195
+ datasetId: version.datasetId,
196
+ versionId: version.versionId
197
+ }
198
+ });
199
+ }
200
+ return resolved;
201
+ }
202
+ function createStepInputs(lakeStorage, resolved) {
203
+ const inputs = {};
204
+ for (const input of resolved) {
205
+ inputs[input.name] = {
206
+ dataset: input.dataset,
207
+ version: input.version,
208
+ readRows(readInput = {}) {
209
+ return lakeStorage.readRows({
210
+ ...readInput,
211
+ datasetId: input.dataset.id,
212
+ versionId: input.version.versionId
213
+ });
214
+ }
215
+ };
216
+ }
217
+ return inputs;
218
+ }
219
+
220
+ // src/execute-run-step.ts
221
+ async function executeRunStep(input) {
222
+ const { runtime, pipeline, step, job, signal, outputDataset, resolvedInputs } = input;
223
+ if (step.executor.kind !== "run") {
224
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${pipeline.id}' step '${step.id}' uses SQL execution, which is not supported by the run step executor.`);
225
+ }
226
+ const logger = input.logSession.withContext({ stepId: step.id });
227
+ let rowsWritten = 0;
228
+ const write = await runtime.lakeStorage.beginWrite({
229
+ dataset: outputDataset,
230
+ mode: step.mode,
231
+ inputs: resolvedInputs.map((resolved) => resolved.ref),
232
+ producer: {
233
+ kind: "pipeline",
234
+ id: pipeline.id,
235
+ runId: job.id,
236
+ stepId: step.id
237
+ }
238
+ });
239
+ try {
240
+ const context = {
241
+ projectId: runtime.id,
242
+ pipelineId: pipeline.id,
243
+ stepId: step.id,
244
+ runId: job.id,
245
+ signal,
246
+ logger,
247
+ inputs: createStepInputs(runtime.lakeStorage, resolvedInputs),
248
+ output: {
249
+ async writeRows(rows) {
250
+ await write.writeRows(countRowsWritten(rows, signal, () => {
251
+ rowsWritten += 1;
252
+ }));
253
+ }
254
+ }
255
+ };
256
+ await step.executor.handler(context);
257
+ throwIfAborted(signal);
258
+ const commit = await write.commit({
259
+ commitMessage: `pipeline ${pipeline.id} step ${step.id} run ${job.id}`
260
+ });
261
+ const { outcome, ...version } = commit;
262
+ return {
263
+ version,
264
+ versionCreated: outcome === "created",
265
+ rowsWritten
266
+ };
267
+ } catch (error) {
268
+ await write.abort().catch(() => {});
269
+ throw error;
270
+ }
271
+ }
272
+ async function* countRowsWritten(rows, signal, onWritten) {
273
+ for await (const row of rows) {
274
+ throwIfAborted(signal);
275
+ yield row;
276
+ onWritten();
277
+ }
278
+ }
279
+
280
+ // src/execute-sql-step.ts
281
+ function hasSqlExecutor(lakeStorage) {
282
+ const sql = "sql" in lakeStorage ? lakeStorage.sql : null;
283
+ return typeof sql === "object" && sql !== null && "execute" in sql && typeof sql.execute === "function";
284
+ }
285
+ function assertSqlModeSupported(input) {
286
+ const supported = input.mode === "append" ? input.capabilities.supportsAppend : input.capabilities.supportsSnapshot;
287
+ if (supported)
288
+ return;
289
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${input.pipelineId}' step '${input.stepId}' writes in ` + `'${input.mode}' mode, which the ${input.dialect} SQL executor does not support.`);
290
+ }
291
+ async function executeSqlStep(input) {
292
+ const { runtime, pipeline, step, job, signal, outputDataset, resolvedInputs } = input;
293
+ if (step.executor.kind !== "sql") {
294
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${pipeline.id}' step '${step.id}' uses run execution, which is not supported by the SQL step executor.`);
295
+ }
296
+ if (!hasSqlExecutor(runtime.lakeStorage)) {
297
+ throw new PipelineWorkerError(`[SixbPipelineWorker] Pipeline '${pipeline.id}' step '${step.id}' requires SQL transform support, but lake storage does not provide lakeStorage.sql.execute(...).`);
298
+ }
299
+ assertSqlModeSupported({
300
+ capabilities: runtime.lakeStorage.sql.capabilities,
301
+ dialect: runtime.lakeStorage.sql.dialect,
302
+ mode: step.mode,
303
+ pipelineId: pipeline.id,
304
+ stepId: step.id
305
+ });
306
+ throwIfAborted(signal);
307
+ const commit = await runtime.lakeStorage.sql.execute({
308
+ sources: Object.fromEntries(resolvedInputs.map((input2) => [
309
+ input2.name,
310
+ {
311
+ dataset: input2.dataset,
312
+ versionId: input2.version.versionId
313
+ }
314
+ ])),
315
+ sql: step.executor.sql,
316
+ target: outputDataset,
317
+ mode: step.mode,
318
+ producer: {
319
+ kind: "pipeline",
320
+ id: pipeline.id,
321
+ runId: job.id,
322
+ stepId: step.id
323
+ },
324
+ commitMessage: `pipeline ${pipeline.id} step ${step.id} run ${job.id}`
325
+ });
326
+ throwIfAborted(signal);
327
+ const { outcome, ...version } = commit;
328
+ return {
329
+ version,
330
+ versionCreated: outcome === "created",
331
+ rowsWritten: version.rowCount
332
+ };
333
+ }
334
+
335
+ // src/run-step.ts
336
+ async function runStep(input) {
337
+ const { runtime, pipeline, step, stepIndex, job, signal } = input;
338
+ const lifecycleContext = {
339
+ stepIndex,
340
+ totalSteps: pipeline.graph.nodes.length
341
+ };
342
+ throwIfAborted(signal);
343
+ const resolvedInputs = await resolveStepInputs({ runtime, pipeline, step });
344
+ const inputRefs = resolvedInputs.map((resolved) => resolved.ref);
345
+ const outputDataset = requireRegisteredDataset({
346
+ dataset: runtime.getDatasetById(step.output.id),
347
+ pipelineId: pipeline.id,
348
+ stepId: step.id,
349
+ role: "output",
350
+ datasetId: step.output.id
351
+ });
352
+ await runtime.lakeStorage.createDataset(outputDataset);
353
+ const stepRunId = `${job.id}:step:${stepIndex + 1}:${step.id}`;
354
+ const startedStepRun = await runtime.pipelineRunsStorage.startStep({
355
+ projectId: runtime.id,
356
+ id: stepRunId,
357
+ pipelineRunId: job.id,
358
+ pipelineId: pipeline.id,
359
+ stepId: step.id,
360
+ datasetId: outputDataset.id,
361
+ mode: step.mode,
362
+ inputs: inputRefs
363
+ });
364
+ await input.onStepStarted?.(startedStepRun, lifecycleContext);
365
+ let committedVersion;
366
+ let rowsWritten;
367
+ try {
368
+ const execution = await executeStep({
369
+ runtime,
370
+ pipeline,
371
+ step,
372
+ job,
373
+ signal,
374
+ logSession: input.logSession,
375
+ outputDataset,
376
+ resolvedInputs
377
+ });
378
+ committedVersion = execution.version;
379
+ rowsWritten = execution.rowsWritten;
380
+ let stepRun;
381
+ try {
382
+ stepRun = await runtime.pipelineRunsStorage.finishStep({
383
+ projectId: runtime.id,
384
+ id: stepRunId,
385
+ status: "succeeded",
386
+ output: {
387
+ datasetId: committedVersion.datasetId,
388
+ versionId: committedVersion.versionId
389
+ },
390
+ rowsWritten
391
+ });
392
+ } catch (error) {
393
+ throw createStepBookkeepingError({
394
+ pipelineId: pipeline.id,
395
+ stepId: step.id,
396
+ runId: stepRunId,
397
+ version: committedVersion,
398
+ cause: error
399
+ });
400
+ }
401
+ await input.onStepFinished?.(stepRun, lifecycleContext);
402
+ return {
403
+ run: stepRun,
404
+ version: committedVersion,
405
+ versionCreated: execution.versionCreated
406
+ };
407
+ } catch (error) {
408
+ if (!committedVersion) {
409
+ const failedStepRun = await runtime.pipelineRunsStorage.finishStep({
410
+ projectId: runtime.id,
411
+ id: stepRunId,
412
+ status: statusForFailure(signal, error),
413
+ rowsWritten,
414
+ error: toPipelineRunFailure(error)
415
+ }).catch(() => null);
416
+ if (failedStepRun) {
417
+ await input.onStepFinished?.(failedStepRun, lifecycleContext);
418
+ }
419
+ }
420
+ throw error;
421
+ }
422
+ }
423
+ async function executeStep(input) {
424
+ switch (input.step.executor.kind) {
425
+ case "run":
426
+ return executeRunStep(input);
427
+ case "sql":
428
+ return executeSqlStep(input);
429
+ }
430
+ }
431
+
432
+ // src/run-pipeline-job.ts
433
+ class PipelineRunAlreadyStartedError extends Error {
434
+ run;
435
+ name = "PipelineRunAlreadyStartedError";
436
+ constructor(run) {
437
+ super(`[SixbPipelineWorker] Pipeline run '${run.id}' has already started.`);
438
+ this.run = run;
439
+ }
440
+ }
441
+ async function runPipelineJob(input) {
442
+ const { runtime, job } = input;
443
+ const signal = input.signal ?? new AbortController().signal;
444
+ const pipeline = requirePipeline(runtime.getPipelineById(job.pipelineId), job);
445
+ const logSession = resolveLogsRuntime(runtime.id, runtime.logs).startExecution({
446
+ kind: "pipeline",
447
+ id: job.id
448
+ });
449
+ const steps = [];
450
+ let startedRun;
451
+ let finalVersion;
452
+ let finished = false;
453
+ throwIfAborted(signal);
454
+ try {
455
+ try {
456
+ startedRun = await runtime.pipelineRunsStorage.start({
457
+ projectId: runtime.id,
458
+ id: job.id,
459
+ pipelineId: pipeline.id
460
+ });
461
+ } catch (error) {
462
+ const existing = await runtime.pipelineRunsStorage.getById({
463
+ projectId: runtime.id,
464
+ id: job.id
465
+ });
466
+ if (existing?.pipelineId === pipeline.id) {
467
+ throw new PipelineRunAlreadyStartedError(existing);
468
+ }
469
+ throw error;
470
+ }
471
+ await input.onRunStarted?.(startedRun);
472
+ for (const [stepIndex, node] of pipeline.graph.nodes.entries()) {
473
+ const stepResult = await runStep({
474
+ runtime,
475
+ pipeline,
476
+ step: node.step,
477
+ stepIndex,
478
+ job,
479
+ signal,
480
+ logSession,
481
+ onStepStarted: input.onStepStarted,
482
+ onStepFinished: input.onStepFinished
483
+ });
484
+ steps.push(stepResult);
485
+ finalVersion = stepResult.version;
486
+ await input.onStepCommitted?.(stepResult);
487
+ }
488
+ let run;
489
+ try {
490
+ run = await runtime.pipelineRunsStorage.finish({
491
+ projectId: runtime.id,
492
+ id: job.id,
493
+ status: "succeeded",
494
+ output: finalVersion ? {
495
+ datasetId: finalVersion.datasetId,
496
+ versionId: finalVersion.versionId
497
+ } : undefined
498
+ });
499
+ } catch (error) {
500
+ if (finalVersion) {
501
+ throw createPipelineBookkeepingError({
502
+ pipelineId: pipeline.id,
503
+ runId: job.id,
504
+ version: finalVersion,
505
+ cause: error
506
+ });
507
+ }
508
+ throw error;
509
+ }
510
+ finished = true;
511
+ return {
512
+ run: {
513
+ ...run,
514
+ finishedAt: requireFinishedAt2(job.id, run.finishedAt)
515
+ },
516
+ steps,
517
+ version: finalVersion
518
+ };
519
+ } catch (error) {
520
+ if (startedRun && !finished) {
521
+ const status = statusForFailure(signal, error);
522
+ try {
523
+ const run = await runtime.pipelineRunsStorage.finish({
524
+ projectId: runtime.id,
525
+ id: job.id,
526
+ status,
527
+ error: toPipelineRunFailure(error)
528
+ });
529
+ if (status === "failed" && run.status === "failed")
530
+ input.onRunFailed?.(error, run);
531
+ } catch {}
532
+ }
533
+ throw error;
534
+ } finally {
535
+ await logSession.flush();
536
+ }
537
+ }
538
+
539
+ // src/worker.ts
540
+ class PipelineWorker extends QueueWorker {
541
+ context;
542
+ sixb;
543
+ constructor(sixb) {
544
+ if (sixb.listPipelines().length === 0) {
545
+ throw new Error("[SixbPipelineWorker] No pipeline definitions are registered.");
546
+ }
547
+ const pipelineRunsStorage = sixb.storage.pipelineRuns;
548
+ if (!pipelineRunsStorage) {
549
+ throw new Error("[SixbPipelineWorker] Pipeline workers require storage.pipelineRuns support.");
550
+ }
551
+ super({
552
+ projectId: sixb.id,
553
+ queue: sixb.queues.pipelines,
554
+ workerId: `pipeline-worker-${sixb.id}`
555
+ });
556
+ this.context = buildPipelineContext(sixb, pipelineRunsStorage);
557
+ this.sixb = sixb;
558
+ }
559
+ async execute(claimed, signal) {
560
+ const { job } = claimed;
561
+ const pipelineJob = {
562
+ id: job.payload.runId ?? `${job.id}:attempt:${job.attempt}`,
563
+ pipelineId: job.payload.pipelineId
564
+ };
565
+ let result;
566
+ try {
567
+ result = await runPipelineJob({
568
+ runtime: this.context,
569
+ job: pipelineJob,
570
+ signal,
571
+ onRunStarted: (run) => emitPipelineRunStarted(this.sixb.events, run),
572
+ onRunFailed: (error, run) => {
573
+ reportRunFailure(this.sixb, error, {
574
+ projectId: this.sixb.id,
575
+ occurredAt: run.finishedAt,
576
+ attempt: job.attempt,
577
+ run: {
578
+ kind: "pipeline",
579
+ runId: run.id,
580
+ pipelineId: run.pipelineId
581
+ }
582
+ });
583
+ },
584
+ onStepStarted: (step, context) => emitPipelineRunStepStarted(this.sixb.events, step, context),
585
+ onStepFinished: (step, context) => emitPipelineRunStepFinished(this.sixb.events, step, context),
586
+ onStepCommitted: (step) => emitDatasetVersionCommitted(this.sixb.events, pipelineJob, step)
587
+ });
588
+ } catch (error) {
589
+ if (error instanceof PipelineRunAlreadyStartedError)
590
+ return;
591
+ throw error;
592
+ }
593
+ await emitPipelineRunFinished(this.sixb.events, {
594
+ id: pipelineJob.id,
595
+ pipelineId: pipelineJob.pipelineId,
596
+ status: "succeeded",
597
+ datasetId: result.version?.datasetId,
598
+ versionId: result.version?.versionId
599
+ });
600
+ }
601
+ async onExecutionError(claimed, _error) {
602
+ const { job } = claimed;
603
+ await emitPipelineRunFinished(this.sixb.events, {
604
+ id: job.payload.runId ?? `${job.id}:attempt:${job.attempt}`,
605
+ pipelineId: job.payload.pipelineId,
606
+ status: "failed"
607
+ });
608
+ return { kind: "fail" };
609
+ }
610
+ async onAbortError(claimed, _error) {
611
+ const { job } = claimed;
612
+ const pipelineJob = {
613
+ id: job.payload.runId ?? `${job.id}:attempt:${job.attempt}`,
614
+ pipelineId: job.payload.pipelineId
615
+ };
616
+ if (!await hasCommittedStep(this.context, pipelineJob.id)) {
617
+ return { kind: "retry" };
618
+ }
619
+ await emitPipelineRunFinished(this.sixb.events, {
620
+ id: pipelineJob.id,
621
+ pipelineId: pipelineJob.pipelineId,
622
+ status: "cancelled"
623
+ });
624
+ return { kind: "fail" };
625
+ }
626
+ }
627
+ function buildPipelineContext(sixb, pipelineRunsStorage) {
628
+ return {
629
+ id: sixb.id,
630
+ pipelineRunsStorage,
631
+ lakeStorage: sixb.lakeStorage,
632
+ logs: sixb.logs,
633
+ getPipelineById(pipelineId) {
634
+ return sixb.getPipelineById(pipelineId);
635
+ },
636
+ getDatasetById(datasetId) {
637
+ return sixb.getDatasetById(datasetId);
638
+ }
639
+ };
640
+ }
641
+ async function hasCommittedStep(context, pipelineRunId) {
642
+ const result = await context.pipelineRunsStorage.listSteps({
643
+ projectId: context.id,
644
+ pipelineRunId,
645
+ statuses: ["succeeded"],
646
+ limit: 1
647
+ });
648
+ return result.steps.some((step) => Boolean(step.output));
649
+ }
650
+ export {
651
+ PipelineWorker
652
+ };
653
+
654
+ //# debugId=068611D3BE49C18D64756E2164756E21