effect-distributed-lock 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Backing.ts +1 -2
- package/src/DistributedSemaphore.ts +36 -27
- package/src/RedisBacking.ts +3 -3
package/package.json
CHANGED
package/src/Backing.ts
CHANGED
|
@@ -74,8 +74,7 @@ export interface DistributedSemaphoreBacking {
|
|
|
74
74
|
/**
|
|
75
75
|
* Optional: Stream of notifications when permits MAY be available.
|
|
76
76
|
*
|
|
77
|
-
* If provided, the semaphore layer uses this
|
|
78
|
-
* of polling. The stream emits a signal whenever permits are released.
|
|
77
|
+
* If provided, the semaphore layer uses this in addition to polling. The stream emits a signal whenever permits are released.
|
|
79
78
|
*
|
|
80
79
|
* Notes:
|
|
81
80
|
* - Multiple waiters may race for permits after a notification
|
|
@@ -153,7 +153,11 @@ export interface DistributedSemaphore {
|
|
|
153
153
|
options?: AcquireOptions
|
|
154
154
|
) => <A, E, R>(
|
|
155
155
|
effect: Effect.Effect<A, E, R>
|
|
156
|
-
) => Effect.Effect<
|
|
156
|
+
) => Effect.Effect<
|
|
157
|
+
A,
|
|
158
|
+
E | LockLostError | SemaphoreBackingError | LockNotAcquiredError,
|
|
159
|
+
R
|
|
160
|
+
>;
|
|
157
161
|
|
|
158
162
|
/**
|
|
159
163
|
* Run an effect only if the specified permits are immediately available.
|
|
@@ -402,7 +406,7 @@ export const make = (
|
|
|
402
406
|
return maybeAcquired.value;
|
|
403
407
|
}).pipe(
|
|
404
408
|
Effect.retry({
|
|
405
|
-
while: (e) => e._tag === "LockNotAcquiredError",
|
|
409
|
+
while: (e) => e._tag === "LockNotAcquiredError" && !resolvedOptions.acquiredExternally,
|
|
406
410
|
schedule: acquireRetryPolicy,
|
|
407
411
|
})
|
|
408
412
|
);
|
|
@@ -412,30 +416,31 @@ export const make = (
|
|
|
412
416
|
}
|
|
413
417
|
|
|
414
418
|
// Push-based acquire: run both poll-based and push-based acquire in parallel, and return the first one to complete
|
|
415
|
-
const pushBasedAcquire =
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
)
|
|
437
|
-
})
|
|
438
|
-
|
|
419
|
+
const pushBasedAcquire = Effect.gen(function* () {
|
|
420
|
+
if (!backing.onPermitsReleased) {
|
|
421
|
+
// SAFETY: We know that onPermitsReleased is provided because we checked it above
|
|
422
|
+
return yield* Effect.dieMessage(
|
|
423
|
+
"Invariant violated: `onPermitsReleased` is not provided when it was expected"
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
return yield* backing.onPermitsReleased(key).pipe(
|
|
427
|
+
Stream.runFoldWhileEffect(
|
|
428
|
+
Option.none<
|
|
429
|
+
Fiber.Fiber<never, LockLostError | SemaphoreBackingError>
|
|
430
|
+
>(),
|
|
431
|
+
Option.isNone, // keep folding while we haven't acquired
|
|
432
|
+
() =>
|
|
433
|
+
tryTake(permits, resolvedOptions).pipe(
|
|
434
|
+
acquireSemaphore.withPermitsIfAvailable(1),
|
|
435
|
+
Effect.map(Option.flatten)
|
|
436
|
+
)
|
|
437
|
+
),
|
|
438
|
+
Effect.flatMap(Option.match({
|
|
439
|
+
onSome: Effect.succeed,
|
|
440
|
+
onNone: () => Effect.dieMessage("Invariant violated: the stream should never return `None`")
|
|
441
|
+
}))
|
|
442
|
+
);
|
|
443
|
+
});
|
|
439
444
|
|
|
440
445
|
// first to succeed (acquire permits) wins
|
|
441
446
|
return yield* Effect.race(pollBasedAcquire, pushBasedAcquire);
|
|
@@ -446,7 +451,11 @@ export const make = (
|
|
|
446
451
|
(permits: number, options?: AcquireOptions) =>
|
|
447
452
|
<A, E, R>(
|
|
448
453
|
effect: Effect.Effect<A, E, R>
|
|
449
|
-
): Effect.Effect<
|
|
454
|
+
): Effect.Effect<
|
|
455
|
+
A,
|
|
456
|
+
E | LockLostError | SemaphoreBackingError | LockNotAcquiredError,
|
|
457
|
+
R
|
|
458
|
+
> =>
|
|
450
459
|
Effect.scoped(
|
|
451
460
|
Effect.gen(function* () {
|
|
452
461
|
const keepAliveFiber = yield* take(permits, options);
|
package/src/RedisBacking.ts
CHANGED
|
@@ -333,10 +333,10 @@ export const layer = (
|
|
|
333
333
|
);
|
|
334
334
|
}).pipe(
|
|
335
335
|
Stream.retry(pushStreamRetrySchedule),
|
|
336
|
+
// If we continue to error, and the schedule has completed,
|
|
337
|
+
// just return a stream that will never emit
|
|
336
338
|
Stream.catchTag("SemaphoreBackingError", () =>
|
|
337
|
-
Stream.
|
|
338
|
-
"Invariant violated: `onPermitsReleased` should never error because it should be retried forever"
|
|
339
|
-
)
|
|
339
|
+
Stream.never
|
|
340
340
|
)
|
|
341
341
|
);
|
|
342
342
|
|