From f7bafe889af34f475c1b664139850cfa708cb573 Mon Sep 17 00:00:00 2001 From: Michael Arnaldi Date: Sun, 11 Aug 2024 10:45:05 +0200 Subject: [PATCH] Avoid automatic propagation of finalizer concurrency, closes #3440 --- .changeset/witty-kings-lie.md | 5 + packages/effect/src/Effect.ts | 119 +++++++++++++++--- packages/effect/src/internal/fiberRuntime.ts | 121 ++++++++++++++----- packages/effect/test/Scope.test.ts | 7 +- 4 files changed, 203 insertions(+), 49 deletions(-) create mode 100644 .changeset/witty-kings-lie.md diff --git a/.changeset/witty-kings-lie.md b/.changeset/witty-kings-lie.md new file mode 100644 index 00000000000..ef1280e0416 --- /dev/null +++ b/.changeset/witty-kings-lie.md @@ -0,0 +1,5 @@ +--- +"effect": minor +--- + +Avoid automatic propagation of finalizer concurrency, closes #3440 diff --git a/packages/effect/src/Effect.ts b/packages/effect/src/Effect.ts index d37b318362b..81c297052b7 100644 --- a/packages/effect/src/Effect.ts +++ b/packages/effect/src/Effect.ts @@ -484,6 +484,7 @@ export const all: < readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined } >(arg: Arg, options?: O) => All.Return = fiberRuntime.all @@ -503,6 +504,7 @@ export const allWith: < readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined } >( options?: O @@ -602,6 +604,7 @@ export declare namespace All { readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined } > = [Arg] extends [ReadonlyArray] ? ReturnTuple, ExtractMode> : [Arg] extends [Iterable] ? ReturnIterable, ExtractMode> @@ -622,6 +625,7 @@ export const allSuccesses: >( | { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ) => Effect>, never, Effect.Context> = fiberRuntime.allSuccesses @@ -678,6 +682,7 @@ export const exists: { | { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): (elements: Iterable) => Effect @@ -688,6 +693,7 @@ export const exists: { | { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): Effect @@ -706,6 +712,7 @@ export const filter: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly negate?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): (elements: Iterable) => Effect, E, R> ( @@ -715,6 +722,7 @@ export const filter: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly negate?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): Effect, E, R> } = fiberRuntime.filter @@ -784,6 +792,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): ( self: S @@ -794,6 +803,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): (self: Iterable) => Effect >( @@ -803,6 +813,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): Effect, E, R> ( @@ -812,6 +823,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): Effect } = fiberRuntime.forEach as any @@ -838,7 +850,11 @@ export const mergeAll: { zero: Z, f: (z: Z, a: Effect.Success, i: number) => Z, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): (elements: Iterable) => Effect, Effect.Context> , Z>( @@ -846,7 +862,11 @@ export const mergeAll: { zero: Z, f: (z: Z, a: Effect.Success, i: number) => Z, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect, Effect.Context> } = fiberRuntime.mergeAll @@ -862,14 +882,22 @@ export const partition: { ( f: (a: A, i: number) => Effect, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): (elements: Iterable) => Effect<[excluded: Array, satisfying: Array], never, R> ( elements: Iterable, f: (a: A, i: number) => Effect, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect<[excluded: Array, satisfying: Array], never, R> } = fiberRuntime.partition @@ -897,7 +925,11 @@ export const reduceEffect: { zero: Effect, f: (acc: NoInfer, a: Effect.Success, i: number) => Z, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): (elements: Iterable) => Effect, R | Effect.Context> , Z, E, R>( @@ -905,7 +937,11 @@ export const reduceEffect: { zero: Effect, f: (acc: NoInfer, a: Effect.Success, i: number) => Z, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect, R | Effect.Context> } = fiberRuntime.reduceEffect @@ -965,6 +1001,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect) => Effect, E, R> ( @@ -973,6 +1010,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect) => Effect ( @@ -982,6 +1020,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect, E, R> ( @@ -991,6 +1030,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): Effect } = fiberRuntime.replicateEffect @@ -1044,6 +1084,7 @@ export const validateAll: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): (elements: Iterable) => Effect, Array, R> ( @@ -1052,6 +1093,7 @@ export const validateAll: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): (elements: Iterable) => Effect, R> ( @@ -1061,6 +1103,7 @@ export const validateAll: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): Effect, Array, R> ( @@ -1070,6 +1113,7 @@ export const validateAll: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): Effect, R> } = fiberRuntime.validateAll @@ -1098,14 +1142,22 @@ export const validateFirst: { ( f: (a: A, i: number) => Effect, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): (elements: Iterable) => Effect, R> ( elements: Iterable, f: (a: A, i: number) => Effect, options?: - | { readonly concurrency?: Concurrency | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect, R> } = fiberRuntime.validateFirst @@ -5347,19 +5399,20 @@ export const validate: { ( that: Effect, options?: { - /** - * @since 2.0.0 - * @category supervision & fibers - */ readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): (self: Effect) => Effect<[A, B], E1 | E, R1 | R> ( self: Effect, that: Effect, options?: - | { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect<[A, B], E | E1, R | R1> } = fiberRuntime.validate @@ -5376,7 +5429,11 @@ export const validateWith: { that: Effect, f: (a: A, b: B) => C, options?: - | { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): (self: Effect) => Effect ( @@ -5384,7 +5441,11 @@ export const validateWith: { that: Effect, f: (a: A, b: B) => C, options?: - | { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect } = fiberRuntime.validateWith @@ -5446,14 +5507,22 @@ export const zip: { ( that: Effect, options?: - | { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): (self: Effect) => Effect<[A, A2], E2 | E, R2 | R> ( self: Effect, that: Effect, options?: - | { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect<[A, A2], E | E2, R | R2> } = fiberRuntime.zipOptions @@ -5482,14 +5551,22 @@ export const zipLeft: { ( that: Effect, options?: - | { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): (self: Effect) => Effect ( self: Effect, that: Effect, options?: - | { readonly concurrent?: boolean | undefined; readonly batching?: boolean | "inherit" | undefined } + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined ): Effect } = fiberRuntime.zipLeftOptions @@ -5520,6 +5597,7 @@ export const zipRight: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect) => Effect ( @@ -5528,6 +5606,7 @@ export const zipRight: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect } = fiberRuntime.zipRightOptions @@ -5572,6 +5651,7 @@ export const zipWith: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect) => Effect ( @@ -5581,6 +5661,7 @@ export const zipWith: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect } = fiberRuntime.zipWithOptions diff --git a/packages/effect/src/internal/fiberRuntime.ts b/packages/effect/src/internal/fiberRuntime.ts index ace835a650b..fa1dd2ef502 100644 --- a/packages/effect/src/internal/fiberRuntime.ts +++ b/packages/effect/src/internal/fiberRuntime.ts @@ -1643,10 +1643,12 @@ export const exists: { (f: (a: A, i: number) => Effect.Effect, options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined }): (elements: Iterable) => Effect.Effect (elements: Iterable, f: (a: A, i: number) => Effect.Effect, options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined }): Effect.Effect } = dual( (args) => Predicate.isIterable(args[0]) && !core.isEffect(args[0]), @@ -1695,12 +1697,14 @@ export const filter = dual< readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly negate?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => (elements: Iterable) => Effect.Effect, E, R>, (elements: Iterable, f: (a: NoInfer, i: number) => Effect.Effect, options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly negate?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined }) => Effect.Effect, E, R> >( (args) => Predicate.isIterable(args[0]) && !core.isEffect(args[0]), @@ -1708,6 +1712,7 @@ export const filter = dual< readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly negate?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined }) => { const predicate = options?.negate ? (a: A, i: number) => core.map(f(a, i), Boolean.not) : f return concurrency.matchSimple( @@ -1767,6 +1772,7 @@ const allValidate = ( readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => { const eitherEffects: Array>> = [] @@ -1816,6 +1822,7 @@ const allEither = ( readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => { const eitherEffects: Array>> = [] @@ -1851,6 +1858,7 @@ export const all = < readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined } >( arg: Arg, @@ -1879,6 +1887,7 @@ export const allWith = < readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined } >(options?: O) => > | Record>>( @@ -1891,6 +1900,7 @@ export const allSuccesses = >( options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect>, never, Effect.Effect.Context> => core.map( @@ -1912,6 +1922,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect.Effect) => Effect.Effect, E, R> ( @@ -1920,6 +1931,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect.Effect) => Effect.Effect ( @@ -1929,6 +1941,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect, E, R> ( @@ -1938,6 +1951,7 @@ export const replicateEffect: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect } = dual( @@ -1953,6 +1967,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): ( self: S @@ -1963,6 +1978,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): (self: Iterable) => Effect.Effect ( @@ -1972,6 +1988,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): Effect.Effect, E, R> ( @@ -1981,6 +1998,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } | undefined ): Effect.Effect, E, R> ( @@ -1990,6 +2008,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect } = dual((args) => Predicate.isIterable(args[0]), ( @@ -1999,6 +2018,7 @@ export const forEach: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => core.withFiberRuntime((r) => { @@ -2009,17 +2029,17 @@ export const forEach: { return concurrency.match( options.concurrency, () => - finalizersMask(ExecutionStrategy.sequential)((restore) => + finalizersMaskInternal(ExecutionStrategy.sequential, options?.concurrentFinalizers)((restore) => isRequestBatchingEnabled ? forEachConcurrentDiscard(self, (a, i) => restore(f(a, i)), true, false, 1) : core.forEachSequentialDiscard(self, (a, i) => restore(f(a, i))) ), () => - finalizersMask(ExecutionStrategy.parallel)((restore) => + finalizersMaskInternal(ExecutionStrategy.parallel, options?.concurrentFinalizers)((restore) => forEachConcurrentDiscard(self, (a, i) => restore(f(a, i)), isRequestBatchingEnabled, false) ), (n) => - finalizersMask(ExecutionStrategy.parallelN(n))((restore) => + finalizersMaskInternal(ExecutionStrategy.parallelN(n), options?.concurrentFinalizers)((restore) => forEachConcurrentDiscard(self, (a, i) => restore(f(a, i)), isRequestBatchingEnabled, false, n) ) ) @@ -2028,17 +2048,17 @@ export const forEach: { return concurrency.match( options?.concurrency, () => - finalizersMask(ExecutionStrategy.sequential)((restore) => + finalizersMaskInternal(ExecutionStrategy.sequential, options?.concurrentFinalizers)((restore) => isRequestBatchingEnabled ? forEachParN(self, 1, (a, i) => restore(f(a, i)), true) : core.forEachSequential(self, (a, i) => restore(f(a, i))) ), () => - finalizersMask(ExecutionStrategy.parallel)((restore) => + finalizersMaskInternal(ExecutionStrategy.parallel, options?.concurrentFinalizers)((restore) => forEachParUnbounded(self, (a, i) => restore(f(a, i)), isRequestBatchingEnabled) ), (n) => - finalizersMask(ExecutionStrategy.parallelN(n))((restore) => + finalizersMaskInternal(ExecutionStrategy.parallelN(n), options?.concurrentFinalizers)((restore) => forEachParN(self, n, (a, i) => restore(f(a, i)), isRequestBatchingEnabled) ) ) @@ -2374,6 +2394,7 @@ export const mergeAll = dual< options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => (elements: Iterable) => Effect.Effect, Effect.Effect.Context>, , Z>( @@ -2383,6 +2404,7 @@ export const mergeAll = dual< options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => Effect.Effect, Effect.Effect.Context> >( @@ -2390,6 +2412,7 @@ export const mergeAll = dual< (elements: Iterable>, zero: Z, f: (z: Z, a: A, i: number) => Z, options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined }) => concurrency.matchSimple( options?.concurrency, @@ -2418,6 +2441,7 @@ export const partition = dual< options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => (elements: Iterable) => Effect.Effect<[excluded: Array, satisfying: Array], never, R>, ( @@ -2426,6 +2450,7 @@ export const partition = dual< options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => Effect.Effect<[excluded: Array, satisfying: Array], never, R> >((args) => Predicate.isIterable(args[0]), (elements, f, options) => @@ -2443,6 +2468,7 @@ export const validateAll = dual< readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } ): (elements: Iterable) => Effect.Effect, Array, R> ( @@ -2451,6 +2477,7 @@ export const validateAll = dual< readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): (elements: Iterable) => Effect.Effect, R> }, @@ -2462,6 +2489,7 @@ export const validateAll = dual< readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect, Array, R> ( @@ -2471,6 +2499,7 @@ export const validateAll = dual< readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard: true + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect, R> } @@ -2480,6 +2509,7 @@ export const validateAll = dual< readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined readonly discard?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined }): Effect.Effect, R> => core.flatMap( partition(elements, f, { @@ -2615,6 +2645,7 @@ export const reduceEffect = dual< options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => (elements: Iterable) => Effect.Effect, R | Effect.Effect.Context>, , Z, E, R>( @@ -2624,6 +2655,7 @@ export const reduceEffect = dual< options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => Effect.Effect, R | Effect.Effect.Context> >((args) => Predicate.isIterable(args[0]) && !core.isEffect(args[0]), ( @@ -2633,6 +2665,7 @@ export const reduceEffect = dual< options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => concurrency.matchSimple( @@ -2713,28 +2746,43 @@ export const parallelNFinalizers = /* @internal */ export const finalizersMask = (strategy: ExecutionStrategy.ExecutionStrategy) => ( - self: (restore: (self: Effect.Effect) => Effect.Effect) => Effect.Effect -): Effect.Effect => - core.contextWithEffect((context) => - Option.match(Context.getOption(context, scopeTag), { - onNone: () => self(identity), - onSome: (scope) => { - const patch = strategy._tag === "Parallel" - ? parallelFinalizers - : strategy._tag === "Sequential" - ? sequentialFinalizers - : parallelNFinalizers(strategy.parallelism) - switch (scope.strategy._tag) { - case "Parallel": - return patch(self(parallelFinalizers)) - case "Sequential": - return patch(self(sequentialFinalizers)) - case "ParallelN": - return patch(self(parallelNFinalizers(scope.strategy.parallelism))) + self: ( + restore: (self: Effect.Effect) => Effect.Effect + ) => Effect.Effect +): Effect.Effect => finalizersMaskInternal(strategy, true)(self) + +/* @internal */ +export const finalizersMaskInternal = + (strategy: ExecutionStrategy.ExecutionStrategy, concurrentFinalizers?: boolean | undefined) => + ( + self: ( + restore: (self: Effect.Effect) => Effect.Effect + ) => Effect.Effect + ): Effect.Effect => + core.contextWithEffect((context) => + Option.match(Context.getOption(context, scopeTag), { + onNone: () => self(identity), + onSome: (scope) => { + if (concurrentFinalizers === true) { + const patch = strategy._tag === "Parallel" + ? parallelFinalizers + : strategy._tag === "Sequential" + ? sequentialFinalizers + : parallelNFinalizers(strategy.parallelism) + switch (scope.strategy._tag) { + case "Parallel": + return patch(self(parallelFinalizers)) + case "Sequential": + return patch(self(sequentialFinalizers)) + case "ParallelN": + return patch(self(parallelNFinalizers(scope.strategy.parallelism))) + } + } else { + return self(identity) + } } - } - }) - ) + }) + ) /* @internal */ export const scopeWith = ( @@ -2798,6 +2846,7 @@ export const validate = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => (self: Effect.Effect) => Effect.Effect<[A, B], E | E1, R | R1>, ( @@ -2806,6 +2855,7 @@ export const validate = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => Effect.Effect<[A, B], E | E1, R | R1> >( @@ -2821,6 +2871,7 @@ export const validateWith = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => (self: Effect.Effect) => Effect.Effect, ( @@ -2830,6 +2881,7 @@ export const validateWith = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => Effect.Effect >((args) => core.isEffect(args[1]), (self, that, f, options) => @@ -2882,10 +2934,12 @@ export const validateFirst = dual< (f: (a: A, i: number) => Effect.Effect, options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined }) => (elements: Iterable) => Effect.Effect, R>, (elements: Iterable, f: (a: A, i: number) => Effect.Effect, options?: { readonly concurrency?: Concurrency | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined }) => Effect.Effect, R> >( (args) => Predicate.isIterable(args[0]), @@ -2927,6 +2981,7 @@ export const zipOptions = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => ( self: Effect.Effect @@ -2937,6 +2992,7 @@ export const zipOptions = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => Effect.Effect<[A, A2], E | E2, R | R2> >((args) => core.isEffect(args[1]), ( @@ -2952,6 +3008,7 @@ export const zipLeftOptions = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => ( self: Effect.Effect @@ -2962,6 +3019,7 @@ export const zipLeftOptions = dual< options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ) => Effect.Effect >( @@ -2981,6 +3039,7 @@ export const zipRightOptions: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect.Effect) => Effect.Effect ( @@ -2989,6 +3048,7 @@ export const zipRightOptions: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect } = dual((args) => core.isEffect(args[1]), ( @@ -2997,6 +3057,7 @@ export const zipRightOptions: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect => { if (options?.concurrent !== true && (options?.batching === undefined || options.batching === false)) { @@ -3013,6 +3074,7 @@ export const zipWithOptions: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): (self: Effect.Effect) => Effect.Effect ( @@ -3022,6 +3084,7 @@ export const zipWithOptions: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect } = dual((args) => core.isEffect(args[1]), ( @@ -3031,12 +3094,14 @@ export const zipWithOptions: { options?: { readonly concurrent?: boolean | undefined readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined } ): Effect.Effect => core.map( all([self, that], { concurrency: options?.concurrent ? 2 : 1, - batching: options?.batching + batching: options?.batching, + concurrentFinalizers: options?.concurrentFinalizers }), ([a, a2]) => f(a, a2) )) diff --git a/packages/effect/test/Scope.test.ts b/packages/effect/test/Scope.test.ts index ca5eb79c52b..36c3fb26de8 100644 --- a/packages/effect/test/Scope.test.ts +++ b/packages/effect/test/Scope.test.ts @@ -66,7 +66,10 @@ describe("Scope", () => { const deferred = yield* $(Deferred.make()) const result = yield* $( Effect.addFinalizer(() => Deferred.succeed(deferred, void 0)), - Effect.zipRight(Effect.addFinalizer(() => Deferred.await(deferred)), { concurrent: true }), + Effect.zipRight(Effect.addFinalizer(() => Deferred.await(deferred)), { + concurrent: true, + concurrentFinalizers: true + }), Effect.scoped, Effect.asVoid ) @@ -79,7 +82,7 @@ describe("Scope", () => { Effect.scoped( pipe( Effect.parallelFinalizers(resource(1, ref)), - Effect.zip(resource(2, ref), { concurrent: true }), + Effect.zip(resource(2, ref), { concurrent: true, concurrentFinalizers: true }), Effect.flatMap(([resource1, resource2]) => pipe( Ref.update(ref, (actions) => [...actions, use(resource1)]),