Hyperlinkv0.8.0-beta.28

ScopedCache

ScopedCache.getconsteffect/ScopedCache.ts:254
<Key, A>(key: Key): <E, R>(
  self: ScopedCache<Key, A, E, R>
) => Effect.Effect<A, E, R>
<Key, A, E, R>(self: ScopedCache<Key, A, E, R>, key: Key): Effect.Effect<
  A,
  E,
  R
>

Gets the value for a key, running the cache lookup when no unexpired entry is present.

When to use

Use to retrieve a scoped cached value by key when a missing or expired entry should run the cache lookup and share the in-flight lookup with concurrent callers.

Details

Concurrent get calls for the same key share the same in-flight lookup. Successful and failed lookup exits are cached according to the configured TTL. If the cache is closed, the effect is interrupted.

export const get: {
  <Key, A>(key: Key): <E, R>(self: ScopedCache<Key, A, E, R>) => Effect.Effect<A, E, R>
  <Key, A, E, R>(self: ScopedCache<Key, A, E, R>, key: Key): Effect.Effect<A, E, R>
} = dual(
  2,
  <Key, A, E, R>(self: ScopedCache<Key, A, E, R>, key: Key): Effect.Effect<A, E, R> =>
    effect.uninterruptibleMask((restore) =>
      core.withFiber((fiber) => {
        const state = self.state
        if (state._tag === "Closed") {
          return effect.interrupt
        }
        const oentry = MutableHashMap.get(state.map, key)
        if (Option.isSome(oentry) && !hasExpired(oentry.value, fiber)) {
          // Move the entry to the end of the map to keep it fresh
          MutableHashMap.remove(state.map, key)
          MutableHashMap.set(state.map, key, oentry.value)
          return restore(Deferred.await(oentry.value.deferred))
        }
        const scope = Scope.makeUnsafe()
        const deferred = Deferred.makeUnsafe<A, E>()
        const entry: Entry<A, E> = {
          expiresAt: undefined,
          deferred,
          scope
        }
        MutableHashMap.set(state.map, key, entry)
        return checkCapacity(fiber, state.map, self.capacity).pipe(
          Option.isSome(oentry) ? effect.flatMap(() => Scope.close(oentry.value.scope, effect.exitVoid)) : identity,
          effect.flatMap(() => Scope.provide(restore(self.lookup(key)), scope)),
          effect.onExit((exit) => {
            Deferred.doneUnsafe(deferred, exit)
            const ttl = self.timeToLive(exit, key)
            if (Duration.isFinite(ttl)) {
              entry.expiresAt = fiber.getRef(effect.ClockRef).currentTimeMillisUnsafe() + Duration.toMillis(ttl)
            }
            return effect.void
          })
        )
      })
    )
)