Hyperlinkv0.8.0-beta.28

LayerRef

LayerRef.makeconsteffect/LayerRef.ts:131
<
  I,
  E,
  R,
  X,
  const Preload extends boolean = never,
  SE = never,
  SR = never
>(
  layer: Layer.Layer<I, E, R>,
  options?:
    | {
        readonly idleTimeToLive?: Duration.Input | undefined
        readonly preload?: Preload | undefined
        readonly invalidationSchedule?:
          | Schedule.Schedule<X, unknown, SE, SR>
          | undefined
      }
    | undefined
): Effect.Effect<
  LayerRef<I, E>,
  [Preload] extends [true] ? E : never,
  Scope.Scope | R | SR
>

Creates a LayerRef from a Layer.

When to use

Use when you have one layer-built resource that should be shared, optionally kept alive while idle, and refreshed on demand.

Details

The layer is built lazily on first use unless preload is true. idleTimeToLive keeps the context cached after it stops being used, and invalidationSchedule can periodically invalidate it. When preload is true, scheduled invalidation also reacquires the context.

Gotchas

Invalidation does not revoke contexts already borrowed by active scopes; those contexts remain usable until their scopes close.

Example (Sharing one layer-built service)

import { Context, Effect, Layer, LayerRef } from "effect"

class Database extends Context.Service<Database, {
  readonly query: Effect.Effect<string>
}>()("Database") {}

const databaseLayer = Layer.succeed(Database, {
  query: Effect.succeed("result")
})

const query = Effect.gen(function*() {
  const database = yield* Database
  return yield* database.query
})

const program = Effect.scoped(
  Effect.gen(function*() {
    const ref = yield* LayerRef.make(databaseLayer, {
      idleTimeToLive: "5 seconds"
    })

    const result = yield* Effect.provide(query, ref.get)

    yield* ref.invalidate

    return result
  })
)
constructorsService
Source effect/LayerRef.ts:13161 lines
export const make = Effect.fnUntraced(
  function*<I, E, R, X, const Preload extends boolean = never, SE = never, SR = never>(
    layer: Layer.Layer<I, E, R>,
    options?: {
      /**
       * Duration to keep the resource alive after it is no longer used.
       */
      readonly idleTimeToLive?: Duration.Input | undefined
      /**
       * Whether to acquire the resource during creation.
       */
      readonly preload?: Preload | undefined
      /**
       * Schedule used to invalidate the cached resource. When `preload` is
       * `true`, each scheduled invalidation also reacquires the resource.
       */
      readonly invalidationSchedule?: Schedule.Schedule<X, unknown, SE, SR> | undefined
    } | undefined
  ): Effect.fn.Return<
    LayerRef<I, E>,
    [Preload] extends [true] ? E : never,
    Scope.Scope | R | SR
  > {
    const context = yield* Effect.context<never>()
    const memoMap = Layer.CurrentMemoMap.forkOrCreate(context)

    const rcRef = yield* RcRef.make({
      acquire: Effect.contextWith((_: Context.Context<Scope.Scope>) =>
        Layer.buildWithMemoMap(layer, memoMap, Context.get(_, Scope.Scope))
      ),
      idleTimeToLive: options?.idleTimeToLive
    })

    const refresh = RcRef.invalidate(rcRef).pipe(
      Effect.andThen(Effect.scoped(RcRef.get(rcRef))),
      Effect.asVoid
    )

    if (options?.preload) {
      yield* refresh as Effect.Effect<void>
    }

    if (options?.invalidationSchedule) {
      const onRefresh = options.preload ? refresh : RcRef.invalidate(rcRef)
      yield* onRefresh.pipe(
        Effect.ignoreCause,
        Effect.schedule(options.invalidationSchedule),
        Effect.forkScoped
      )
    }

    return identity<LayerRef<I, any>>({
      [TypeId]: TypeId,
      rcRef,
      get: Layer.effectContext(RcRef.get(rcRef)),
      contextEffect: RcRef.get(rcRef),
      invalidate: RcRef.invalidate(rcRef),
      refresh
    })
  }
)
Referenced by 1 symbols