@effect/workflow 0.14.0 → 0.15.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/src/Workflow.ts CHANGED
@@ -16,7 +16,7 @@ import * as PrimaryKey from "effect/PrimaryKey"
16
16
  import type * as Schedule from "effect/Schedule"
17
17
  import * as Schema from "effect/Schema"
18
18
  import type * as AST from "effect/SchemaAST"
19
- import type * as Scope from "effect/Scope"
19
+ import * as Scope from "effect/Scope"
20
20
  import { makeHashDigest } from "./internal/crypto.js"
21
21
  import type { WorkflowEngine, WorkflowInstance } from "./WorkflowEngine.js"
22
22
 
@@ -537,6 +537,14 @@ export const intoResult = <A, E, R>(
537
537
  ? Effect.failCause(cause as Cause.Cause<never>)
538
538
  : Effect.succeed(new Complete({ exit: Exit.failCause(cause) }))
539
539
  }),
540
+ Effect.onExit((exit) => {
541
+ if (Exit.isFailure(exit)) {
542
+ return Scope.close(instance.scope, exit)
543
+ } else if (exit.value._tag === "Complete") {
544
+ return Scope.close(instance.scope, exit.value.exit)
545
+ }
546
+ return Effect.void
547
+ }),
540
548
  Effect.uninterruptible
541
549
  )
542
550
  })
@@ -572,6 +580,53 @@ export const wrapActivityResult = <A, E, R>(
572
580
  })
573
581
  })
574
582
 
583
+ /**
584
+ * Accesses the workflow scope.
585
+ *
586
+ * The workflow scope is only closed when the workflow execution fully
587
+ * completes.
588
+ *
589
+ * @since 1.0.0
590
+ * @category Scope
591
+ */
592
+ export const scope: Effect.Effect<
593
+ Scope.Scope,
594
+ never,
595
+ WorkflowInstance
596
+ > = Effect.map(InstanceTag, (instance) => instance.scope as Scope.Scope)
597
+
598
+ /**
599
+ * Provides the workflow scope to the given effect.
600
+ *
601
+ * The workflow scope is only closed when the workflow execution fully
602
+ * completes.
603
+ *
604
+ * @since 1.0.0
605
+ * @category Scope
606
+ */
607
+ export const provideScope = <A, E, R>(
608
+ effect: Effect.Effect<A, E, R>
609
+ ): Effect.Effect<A, E, Exclude<R, Scope.Scope> | WorkflowInstance> =>
610
+ Effect.flatMap(scope, (scope) => Scope.extend(effect, scope))
611
+
612
+ /**
613
+ * @since 1.0.0
614
+ * @category Scope
615
+ */
616
+ export const addFinalizer: <R>(
617
+ f: (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, R>
618
+ ) => Effect.Effect<
619
+ void,
620
+ never,
621
+ WorkflowInstance | R
622
+ > = Effect.fnUntraced(function*<R>(
623
+ f: (exit: Exit.Exit<unknown, unknown>) => Effect.Effect<void, never, R>
624
+ ) {
625
+ const scope = (yield* InstanceTag).scope
626
+ const runtime = yield* Effect.runtime<R>()
627
+ yield* Scope.addFinalizerExit(scope, (exit) => Effect.provide(f(exit), runtime))
628
+ })
629
+
575
630
  /**
576
631
  * Add compensation logic to an effect inside a Workflow. The compensation finalizer will be
577
632
  * called if the entire workflow fails, allowing you to perform cleanup or
@@ -622,14 +677,7 @@ export const withCompensation: {
622
677
  Effect.uninterruptibleMask((restore) =>
623
678
  Effect.tap(
624
679
  restore(effect),
625
- (value) =>
626
- Effect.contextWithEffect((context: Context.Context<WorkflowInstance>) =>
627
- Effect.addFinalizer((exit) =>
628
- Exit.isSuccess(exit) || Context.get(context, InstanceTag).suspended
629
- ? Effect.void
630
- : compensation(value, exit.cause)
631
- )
632
- )
680
+ (value) => addFinalizer((exit) => Exit.isSuccess(exit) ? Effect.void : compensation(value, exit.cause))
633
681
  )
634
682
  ))
635
683
 
@@ -11,7 +11,7 @@ import * as Layer from "effect/Layer"
11
11
  import * as Option from "effect/Option"
12
12
  import * as Schedule from "effect/Schedule"
13
13
  import * as Schema from "effect/Schema"
14
- import type * as Scope from "effect/Scope"
14
+ import * as Scope from "effect/Scope"
15
15
  import type * as Activity from "./Activity.js"
16
16
  import type { DurableClock } from "./DurableClock.js"
17
17
  import type * as DurableDeferred from "./DurableDeferred.js"
@@ -199,6 +199,11 @@ export class WorkflowInstance extends Context.Tag("@effect/workflow/WorkflowEngi
199
199
  */
200
200
  readonly workflow: Workflow.Any
201
201
 
202
+ /**
203
+ * The workflow scope, that represents the lifetime of the workflow.
204
+ */
205
+ readonly scope: Scope.CloseableScope
206
+
202
207
  /**
203
208
  * Whether the workflow has requested to be suspended.
204
209
  */
@@ -228,6 +233,7 @@ export class WorkflowInstance extends Context.Tag("@effect/workflow/WorkflowEngi
228
233
  return WorkflowInstance.of({
229
234
  executionId,
230
235
  workflow,
236
+ scope: Effect.runSync(Scope.make()),
231
237
  suspended: false,
232
238
  interrupted: false,
233
239
  cause: undefined,