Hyperlinkv0.8.0-beta.28

Channel

Channel.mergeAllconsteffect/Channel.ts:5944
(options: {
  readonly concurrency: number | "unbounded"
  readonly bufferSize?: number | undefined
  readonly switch?: boolean | undefined
}): <
  OutElem,
  OutErr1,
  OutDone1,
  InElem1,
  InErr1,
  InDone1,
  Env1,
  OutErr,
  OutDone,
  InElem,
  InErr,
  InDone,
  Env
>(
  channels: Channel<
    Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
    OutErr,
    OutDone,
    InElem,
    InErr,
    InDone,
    Env
  >
) => Channel<
  OutElem,
  OutErr1 | OutErr,
  OutDone,
  InElem & InElem1,
  InErr & InErr1,
  InDone & InDone1,
  Env1 | Env
>
<
  OutElem,
  OutErr1,
  OutDone1,
  InElem1,
  InErr1,
  InDone1,
  Env1,
  OutErr,
  OutDone,
  InElem,
  InErr,
  InDone,
  Env
>(
  channels: Channel<
    Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
    OutErr,
    OutDone,
    InElem,
    InErr,
    InDone,
    Env
  >,
  options: {
    readonly concurrency: number | "unbounded"
    readonly bufferSize?: number | undefined
    readonly switch?: boolean | undefined
  }
): Channel<
  OutElem,
  OutErr1 | OutErr,
  OutDone,
  InElem & InElem1,
  InErr & InErr1,
  InDone & InDone1,
  Env1 | Env
>

Merges multiple channels with specified concurrency and buffering options.

When to use

Use when channel outputs are themselves channels and multiple inner channels should run with configured concurrency and buffering.

Example (Merging nested channels)

import { Channel, Data } from "effect"

class MergeAllError extends Data.TaggedError("MergeAllError")<{
  readonly reason: string
}> {}

// Create channels that output other channels
const nestedChannels = Channel.fromIterable([
  Channel.fromIterable([1, 2]),
  Channel.fromIterable([3, 4]),
  Channel.fromIterable([5, 6])
])

// Merge all channels with bounded concurrency
const mergedChannel = Channel.mergeAll({
  concurrency: 2,
  bufferSize: 16
})(nestedChannels)

// Outputs: 1, 2, 3, 4, 5, 6 (order may vary due to concurrency)
combining
Source effect/Channel.ts:5944136 lines
export const mergeAll: {
  (options: {
    readonly concurrency: number | "unbounded"
    readonly bufferSize?: number | undefined
    readonly switch?: boolean | undefined
  }): <OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1, OutErr, OutDone, InElem, InErr, InDone, Env>(
    channels: Channel<
      Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
      OutErr,
      OutDone,
      InElem,
      InErr,
      InDone,
      Env
    >
  ) => Channel<
    OutElem,
    OutErr1 | OutErr,
    OutDone,
    InElem & InElem1,
    InErr & InErr1,
    InDone & InDone1,
    Env1 | Env
  >
  <OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1, OutErr, OutDone, InElem, InErr, InDone, Env>(
    channels: Channel<
      Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
      OutErr,
      OutDone,
      InElem,
      InErr,
      InDone,
      Env
    >,
    options: {
      readonly concurrency: number | "unbounded"
      readonly bufferSize?: number | undefined
      readonly switch?: boolean | undefined
    }
  ): Channel<
    OutElem,
    OutErr1 | OutErr,
    OutDone,
    InElem & InElem1,
    InErr & InErr1,
    InDone & InDone1,
    Env1 | Env
  >
} = dual(
  2,
  <OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1, OutErr, OutDone, InElem, InErr, InDone, Env>(
    channels: Channel<
      Channel<OutElem, OutErr1, OutDone1, InElem1, InErr1, InDone1, Env1>,
      OutErr,
      OutDone,
      InElem,
      InErr,
      InDone,
      Env
    >,
    { bufferSize = 16, concurrency, switch: switch_ = false }: {
      readonly concurrency: number | "unbounded"
      readonly bufferSize?: number | undefined
      readonly switch?: boolean | undefined
    }
  ): Channel<
    OutElem,
    OutErr1 | OutErr,
    OutDone,
    InElem & InElem1,
    InErr & InErr1,
    InDone & InDone1,
    Env1 | Env
  > =>
    fromTransformBracket(
      Effect.fnUntraced(function*(upstream, scope, forkedScope) {
        const concurrencyN = concurrency === "unbounded"
          ? Number.MAX_SAFE_INTEGER
          : Math.max(1, concurrency)
        const semaphore = switch_ ? undefined : Semaphore.makeUnsafe(concurrencyN)
        const doneLatch = yield* Latch.make(true)
        const fibers = new Set<Fiber.Fiber<any, any>>()

        const queue = yield* Queue.bounded<OutElem, OutErr | OutErr1 | Cause.Done<OutDone>>(
          bufferSize
        )
        yield* Scope.addFinalizer(forkedScope, Queue.shutdown(queue))

        const pull = yield* toTransform(channels)(upstream, scope)

        yield* Effect.gen(function*() {
          while (true) {
            if (semaphore) yield* semaphore.take(1)
            const channel = yield* pull
            const childScope = Scope.forkUnsafe(forkedScope)
            const childPull = yield* toTransform(channel)(upstream, childScope)

            while (fibers.size >= concurrencyN) {
              const fiber = Iterable.headUnsafe(fibers)
              fibers.delete(fiber)
              if (fibers.size === 0) yield* doneLatch.open
              yield* Fiber.interrupt(fiber)
            }

            const fiber = yield* childPull.pipe(
              Effect.tap(() => Effect.yieldNow),
              Effect.flatMap((value) => Queue.offer(queue, value)),
              Effect.forever({ disableYield: true }),
              Effect.onError(Effect.fnUntraced(function*(cause) {
                const halt = Pull.filterDone(cause)
                yield* Effect.exit(Scope.close(
                  childScope,
                  !Result.isFailure(halt) ? Exit.succeed(halt.success.value) : Exit.failCause(halt.failure)
                ))
                if (!fibers.has(fiber)) return
                fibers.delete(fiber)
                if (semaphore) yield* semaphore.release(1)
                if (fibers.size === 0) yield* doneLatch.open
                if (Result.isSuccess(halt)) return
                return yield* Queue.failCause(queue, cause as any)
              })),
              Effect.forkChild
            )

            doneLatch.closeUnsafe()
            fibers.add(fiber)
          }
        }).pipe(
          Effect.catchCause((cause) => doneLatch.whenOpen(Queue.failCause(queue, cause))),
          Effect.forkIn(forkedScope)
        )

        return Queue.take(queue)
      })
    )
)
Referenced by 2 symbols