@effect/cluster 0.52.6 → 0.52.7

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/src/Sharding.ts CHANGED
@@ -42,6 +42,7 @@ import { make as makeEntityId } from "./EntityId.js"
42
42
  import * as Envelope from "./Envelope.js"
43
43
  import * as EntityManager from "./internal/entityManager.js"
44
44
  import { EntityReaper } from "./internal/entityReaper.js"
45
+ import { joinAllDiscard } from "./internal/fiber.js"
45
46
  import { hashString } from "./internal/hash.js"
46
47
  import { internalInterruptors } from "./internal/interruptors.js"
47
48
  import { ResourceMap } from "./internal/resourceMap.js"
@@ -263,45 +264,37 @@ const make = Effect.gen(function*() {
263
264
  const releaseShardsMap = yield* FiberMap.make<ShardId>()
264
265
  const releaseShard = Effect.fnUntraced(
265
266
  function*(shardId: ShardId) {
266
- yield* Effect.forEach(
267
- entityManagers.values(),
268
- (state) =>
269
- state.status === "closed" ? Effect.void : state.manager.interruptShard(shardId).pipe(
270
- Effect.withSpan("EntityManager.interruptShard", {
271
- captureStackTrace: false,
272
- attributes: { entityType: state.entity.type }
273
- })
274
- ),
275
- { concurrency: "unbounded", discard: true }
276
- ).pipe(
277
- Effect.timeout(config.entityTerminationTimeout)
278
- )
267
+ const fibers = Arr.empty<Fiber.RuntimeFiber<void>>()
268
+ for (const state of entityManagers.values()) {
269
+ if (state.status === "closed") continue
270
+ fibers.push(yield* Effect.fork(state.manager.interruptShard(shardId)))
271
+ }
272
+ yield* joinAllDiscard(fibers)
279
273
  yield* runnerStorage.release(selfAddress, shardId)
280
274
  MutableHashSet.remove(releasingShards, shardId)
281
275
  yield* storage.unregisterShardReplyHandlers(shardId)
282
276
  },
283
277
  Effect.sandbox,
284
- Effect.tapError((cause) => Effect.logDebug(`Could not release shard, retrying`, cause)),
285
- Effect.eventually,
286
278
  (effect, shardId) =>
287
279
  effect.pipe(
288
- Effect.annotateLogs({
289
- package: "@effect/cluster",
290
- module: "Sharding",
291
- fiber: "releaseShard",
292
- runner: selfAddress,
293
- shardId
294
- }),
295
- Effect.withSpan("Sharding.releaseShard", { captureStackTrace: false }),
296
- Effect.annotateSpans({
297
- shardId,
298
- runner: selfAddress
299
- }),
280
+ Effect.tapError((cause) =>
281
+ Effect.logDebug(`Could not release shard, retrying`, cause).pipe(
282
+ Effect.annotateLogs({
283
+ package: "@effect/cluster",
284
+ module: "Sharding",
285
+ fiber: "releaseShard",
286
+ runner: selfAddress,
287
+ shardId
288
+ })
289
+ )
290
+ ),
291
+ Effect.eventually,
300
292
  FiberMap.run(releaseShardsMap, shardId, { onlyIfMissing: true })
301
293
  )
302
294
  )
303
295
  const releaseShards = Effect.gen(function*() {
304
296
  for (const shardId of releasingShards) {
297
+ if (FiberMap.unsafeHas(releaseShardsMap, shardId)) continue
305
298
  yield* releaseShard(shardId)
306
299
  }
307
300
  })
@@ -1115,8 +1108,8 @@ const make = Effect.gen(function*() {
1115
1108
 
1116
1109
  yield* Scope.addFinalizer(
1117
1110
  yield* Effect.scope,
1118
- Effect.withFiberRuntime((fiber) => {
1119
- internalInterruptors.add(fiber.id())
1111
+ Effect.fiberIdWith((fiberId) => {
1112
+ internalInterruptors.add(fiberId)
1120
1113
  return Effect.void
1121
1114
  })
1122
1115
  )
@@ -1384,8 +1377,7 @@ const make = Effect.gen(function*() {
1384
1377
  )
1385
1378
  }
1386
1379
 
1387
- const fiberId = yield* Effect.fiberId
1388
- internalInterruptors.add(fiberId)
1380
+ internalInterruptors.add(yield* Effect.fiberId)
1389
1381
  if (isShutdown.current) return
1390
1382
 
1391
1383
  MutableRef.set(isShutdown, true)
@@ -9,12 +9,13 @@ import type { DurationInput } from "effect/Duration"
9
9
  import * as Effect from "effect/Effect"
10
10
  import * as Equal from "effect/Equal"
11
11
  import * as Exit from "effect/Exit"
12
- import * as FiberMap from "effect/FiberMap"
12
+ import type * as Fiber from "effect/Fiber"
13
13
  import * as FiberRef from "effect/FiberRef"
14
14
  import { identity } from "effect/Function"
15
15
  import * as HashMap from "effect/HashMap"
16
16
  import * as Metric from "effect/Metric"
17
17
  import * as Option from "effect/Option"
18
+ import * as Runtime from "effect/Runtime"
18
19
  import * as Schedule from "effect/Schedule"
19
20
  import * as Schema from "effect/Schema"
20
21
  import * as Scope from "effect/Scope"
@@ -35,6 +36,7 @@ import type { Sharding } from "../Sharding.js"
35
36
  import { ShardingConfig } from "../ShardingConfig.js"
36
37
  import * as Snowflake from "../Snowflake.js"
37
38
  import { EntityReaper } from "./entityReaper.js"
39
+ import { joinAllDiscard } from "./fiber.js"
38
40
  import { internalInterruptors } from "./interruptors.js"
39
41
  import { ResourceMap } from "./resourceMap.js"
40
42
  import { ResourceRef } from "./resourceRef.js"
@@ -435,44 +437,31 @@ export const make = Effect.fnUntraced(function*<
435
437
  )
436
438
  }
437
439
 
438
- const entityRemovalMap = yield* FiberMap.make<EntityAddress>()
439
-
440
- const interruptShard = (shardId: ShardId) =>
441
- Effect.suspend(function loop(): Effect.Effect<void> {
442
- const toAwait = Arr.empty<Effect.Effect<void>>()
443
- activeServers.forEach((state) => {
444
- if (shardId[Equal.symbol](state.address.shardId)) {
445
- toAwait.push(
446
- FiberMap.run(
447
- entityRemovalMap,
448
- state.address,
449
- entities.removeIgnore(state.address),
450
- { onlyIfMissing: true }
451
- )
452
- )
453
- }
454
- })
455
- serverCloseLatches.forEach((latch, address) => {
456
- if (shardId[Equal.symbol](address.shardId)) {
457
- toAwait.push(latch.await)
458
- }
459
- })
460
- if (toAwait.length === 0) {
461
- return Effect.void
462
- }
463
- return Effect.flatMap(
464
- Effect.all(toAwait, {
465
- concurrency: "unbounded",
466
- discard: true
467
- }),
468
- loop
469
- )
470
- })
471
-
472
440
  const decodeMessage = Schema.decode(makeMessageSchema(entity))
473
441
 
442
+ const runFork = Runtime.runFork(
443
+ yield* Effect.runtime<never>().pipe(
444
+ Effect.interruptible
445
+ )
446
+ )
447
+
474
448
  return identity<EntityManager>({
475
- interruptShard,
449
+ interruptShard: (shardId: ShardId) =>
450
+ Effect.suspend(function loop(): Effect.Effect<void> {
451
+ const fibers = Arr.empty<Fiber.RuntimeFiber<void>>()
452
+ activeServers.forEach((state) => {
453
+ if (shardId[Equal.symbol](state.address.shardId)) {
454
+ fibers.push(runFork(entities.removeIgnore(state.address)))
455
+ }
456
+ })
457
+ serverCloseLatches.forEach((latch, address) => {
458
+ if (shardId[Equal.symbol](address.shardId)) {
459
+ fibers.push(runFork(latch.await))
460
+ }
461
+ })
462
+ if (fibers.length === 0) return Effect.void
463
+ return Effect.flatMap(joinAllDiscard(fibers), loop)
464
+ }),
476
465
  isProcessingFor(message, options) {
477
466
  if (options?.excludeReplies !== true && processedRequestIds.has(message.envelope.requestId)) {
478
467
  return true
@@ -0,0 +1,35 @@
1
+ import * as Cause from "effect/Cause"
2
+ import * as Effect from "effect/Effect"
3
+ import type * as Exit from "effect/Exit"
4
+ import type * as Fiber from "effect/Fiber"
5
+
6
+ /** @internal */
7
+ export const joinAllDiscard = <A, E>(fibers: ReadonlyArray<Fiber.RuntimeFiber<A, E>>) =>
8
+ Effect.async<void, E>((resume) => {
9
+ let cause: Cause.Cause<E> | undefined = undefined
10
+ let i = 0
11
+ function loop() {
12
+ while (i < fibers.length) {
13
+ const fiber = fibers[i]
14
+ const exit = fiber.unsafePoll()
15
+ if (exit) {
16
+ i++
17
+ if (exit._tag === "Success") continue
18
+ cause = cause ? Cause.parallel(cause, exit.cause) : exit.cause
19
+ continue
20
+ }
21
+ fiber.addObserver(onExit)
22
+ return
23
+ }
24
+ resume(cause ? Effect.failCause(cause) : Effect.void)
25
+ }
26
+ function onExit(exit: Exit.Exit<A, E>) {
27
+ i++
28
+ if (exit._tag === "Failure") {
29
+ cause = cause ? Cause.parallel(cause, exit.cause) : exit.cause
30
+ }
31
+ loop()
32
+ }
33
+ loop()
34
+ return Effect.sync(() => fibers[i].removeObserver(onExit))
35
+ })