| 58 | }) |
| 59 | |
| 60 | const fixedWindow = (limit: number, window: DurationInput): Effect.Effect< |
| 61 | RateLimiter.RateLimiter, |
| 62 | never, |
| 63 | Scope.Scope |
| 64 | > => |
| 65 | Effect.gen(function*() { |
| 66 | const semaphore = yield* Effect.makeSemaphore(limit) |
| 67 | const latch = yield* Effect.makeSemaphore(0) |
| 68 | yield* pipe( |
| 69 | latch.take(1), |
| 70 | Effect.zipRight(Effect.sleep(window)), |
| 71 | Effect.zipRight(latch.releaseAll), |
| 72 | Effect.zipRight(semaphore.releaseAll), |
| 73 | Effect.forever, |
| 74 | Effect.forkScoped, |
| 75 | Effect.interruptible |
| 76 | ) |
| 77 | const take = Effect.uninterruptibleMask((restore) => |
| 78 | Effect.flatMap( |
| 79 | FiberRef.get(currentCost), |
| 80 | (cost) => Effect.zipRight(restore(semaphore.take(cost)), latch.release(1)) |
| 81 | ) |
| 82 | ) |
| 83 | return (effect) => Effect.zipRight(take, effect) |
| 84 | }) |
| 85 | |
| 86 | /** @internal */ |
| 87 | const currentCost = globalValue( |