Skip to main content
effect-zio

Fibers and Forking

Step 8 of 15

Fibers and Forking

Both Effect and ZIO use fibers for lightweight concurrent execution. The concepts are identical; the APIs differ slightly.

Forking Effects

ZIO (Scala)
// ZIO: fork to run concurrently
val fiber: ZIO[Any, Nothing, Fiber[Nothing, Int]] =
  ZIO.succeed(42).fork

// Fork multiple effects
val program: ZIO[Any, Nothing, Unit] =
  for {
    fiber1 <- ZIO.succeed(1).fork
    fiber2 <- ZIO.succeed(2).fork
    _      <- fiber1.join
    _      <- fiber2.join
  } yield ()

ZIO.fork returns ZIO[..., Fiber[...]]

Effect (TypeScript)
// Effect: Effect.fork to run concurrently
const fiber: Effect<Fiber<never, number>, never, never> =
  Effect.fork(Effect.succeed(42))

// Fork multiple effects
const program: Effect<void, never, never> =
  Effect.gen(function* () {
    const fiber1 = yield* Effect.fork(
      Effect.succeed(1)
    )
    const fiber2 = yield* Effect.fork(
      Effect.succeed(2)
    )
    yield* Fiber.join(fiber1)
    yield* Fiber.join(fiber2)
  })

Effect.fork returns Effect<Fiber<...>>

Joining Fibers

ZIO (Scala)
// ZIO: fiber.join, fiber.await
val program: ZIO[Any, Nothing, Int] =
  for {
    fiber <- ZIO.succeed(42).fork
    // join: wait for result
    result <- fiber.join
  } yield result

// await: get Exit value
val program2: ZIO[Any, Nothing, Exit[Nothing, Int]] =
  for {
    fiber <- ZIO.succeed(42).fork
    exit   <- fiber.await
  } yield exit

fiber.join: ZIO[..., A], fiber.await: ZIO[..., Exit[E, A]]

Effect (TypeScript)
// Effect: Fiber.join, Fiber.await
const program: Effect<number, never, never> =
  Effect.gen(function* () {
    const fiber = yield* Effect.fork(
      Effect.succeed(42)
    )
    // Fiber.join: wait for result
    const result = yield* Fiber.join(fiber)
    return result
  })

// Fiber.await: get Exit value
const program2: Effect<
  Exit<never, number>,
  never,
  never
> = Effect.gen(function* () {
    const fiber = yield* Effect.fork(
      Effect.succeed(42)
    )
    const exit = yield* Fiber.await(fiber)
    return exit
  })

Fiber.join: Effect<A>, Fiber.await: Effect<Exit<E, A>>

Interrupting Fibers

ZIO (Scala)
// ZIO: fiber.interrupt
val program: ZIO[Any, Nothing, Unit] =
  for {
    fiber <- ZIO.sleep(10.seconds).fork
    _      <- fiber.interrupt
  } yield ()

// Handle interruption
val withInterruption: ZIO[Any, Nothing, Unit] =
  ZIO.sleep(10.seconds)
    .onInterrupt(
      ZIO.succeed(println("Interrupted!"))
    )
    .fork
    .flatMap(_.interrupt)

fiber.interrupt: ZIO[..., Exit[Nothing, Unit]]

Effect (TypeScript)
// Effect: Fiber.interrupt
const program: Effect<void, never, never> =
  Effect.gen(function* () {
    const fiber = yield* Effect.fork(
      Effect.sleep("10 seconds")
    )
    yield* Fiber.interrupt(fiber)
  })

// Handle interruption
const withInterruption: Effect<void, never, never> =
  Effect.fork(
    Effect.onInterrupt(
      Effect.sleep("10 seconds"),
      () =>
        Effect.sync(() =>
          console.log("Interrupted!")
        )
    )
  ).pipe(
    Effect.flatMap(Fiber.interrupt)
  )

Fiber.interrupt(fiber): Effect<Exit<never, void>>

Daemon Fibers

ZIO (Scala)
// ZIO: forkDaemon for background fibers
val program: ZIO[Any, Nothing, Int] =
  for {
    _ <- ZIO.sleep(1.second).forkDaemon
    _ <- ZIO.sleep(2.seconds)
  } yield 42
// Daemon fiber auto-canceled when parent ends

forkDaemon: auto-cancel on parent completion

Effect (TypeScript)
// Effect: Effect.forkDaemon
const program: Effect<number, never, never> =
  Effect.gen(function* () {
    yield* Effect.forkDaemon(
      Effect.sleep("1 second")
    )
    yield* Effect.sleep("2 seconds")
    return 42
  })
// Daemon fiber auto-canceled when parent ends

Effect.forkDaemon: auto-cancel on parent completion

Fiber API

ZIO (Scala)
// ZIO: Fiber operations
val program: ZIO[Any, Nothing, Unit] =
  for {
    fiber <- ZIO.succeed(42).fork
    id     = fiber.id
    status <- fiber.status
    _      <- fiber.interruptFork
    _      <- fiber.join
  } yield ()

fiber.id, fiber.status, fiber.interruptFork

Effect (TypeScript)
// Effect: Fiber operations
const program: Effect<void, never, never> =
  Effect.gen(function* () {
    const fiber = yield* Effect.fork(
      Effect.succeed(42)
    )
    const id = fiber.id()
    const status = yield* Fiber.status(fiber)
    yield* Fiber.interruptFork(fiber)
    yield* Fiber.join(fiber)
  })

fiber.id(), Fiber.status(fiber), Fiber.interruptFork(fiber)

Concurrency Quick Reference

ZIOEffectPurpose
fa.forkEffect.fork(fa)Run concurrently
fa.forkDaemonEffect.forkDaemon(fa)Run as daemon
fiber.joinFiber.join(fiber)Wait for result
fiber.awaitFiber.await(fiber)Get Exit value
fiber.interruptFiber.interrupt(fiber)Cancel fiber
fiber.statusFiber.status(fiber)Get status
fa.onInterrupt(f)Effect.onInterrupt(fa, f)Handle interruption
TIP:

Fibers are lightweight — you can fork millions of them. Use Effect.fork for independent concurrent work and Effect.all with concurrency options for coordinating multiple effects.

Next: Concurrent Combinators →