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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-distributed-lock",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "A distributed semaphore library for Effect with pluggable backends",
5
5
  "license": "MIT",
6
6
  "repository": {
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 for efficient waiting instead
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<A, E | LockLostError | SemaphoreBackingError | LockNotAcquiredError, R>;
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 = backing.onPermitsReleased
416
- ? Effect.gen(function* () {
417
- if (!backing.onPermitsReleased) {
418
- // SAFETY: We know that onPermitsReleased is provided because we checked it above
419
- return yield* Effect.dieMessage(
420
- "Invariant violated: `onPermitsReleased` is not provided"
421
- );
422
- }
423
- return yield* backing.onPermitsReleased(key).pipe(
424
- Stream.runFoldWhileEffect(
425
- Option.none<
426
- Fiber.Fiber<never, LockLostError | SemaphoreBackingError>
427
- >(),
428
- Option.isNone, // keep folding while we haven't acquired
429
- () =>
430
- tryTake(permits, resolvedOptions).pipe(
431
- acquireSemaphore.withPermitsIfAvailable(1),
432
- Effect.map(Option.flatten)
433
- )
434
- ),
435
- Effect.map(Option.getOrThrow)
436
- );
437
- })
438
- : Effect.never;
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<A, E | LockLostError | SemaphoreBackingError | LockNotAcquiredError, R> =>
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);
@@ -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.dieMessage(
338
- "Invariant violated: `onPermitsReleased` should never error because it should be retried forever"
339
- )
339
+ Stream.never
340
340
  )
341
341
  );
342
342