@effect/cluster 0.46.4 → 0.47.0

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.
@@ -4,6 +4,8 @@
4
4
  import * as Context from "effect/Context"
5
5
  import * as Effect from "effect/Effect"
6
6
  import * as Layer from "effect/Layer"
7
+ import * as RcMap from "effect/RcMap"
8
+ import type * as Scope from "effect/Scope"
7
9
  import * as MessageStorage from "./MessageStorage.js"
8
10
  import type { RunnerAddress } from "./RunnerAddress.js"
9
11
  import * as Runners from "./Runners.js"
@@ -22,10 +24,46 @@ import type { ShardingConfig } from "./ShardingConfig.js"
22
24
  export class RunnerHealth extends Context.Tag("@effect/cluster/RunnerHealth")<
23
25
  RunnerHealth,
24
26
  {
27
+ /**
28
+ * Used to indicate that a Runner is connected to this host and is healthy,
29
+ * while the Scope is active.
30
+ */
31
+ readonly onConnection: (address: RunnerAddress) => Effect.Effect<void, never, Scope.Scope>
25
32
  readonly isAlive: (address: RunnerAddress) => Effect.Effect<boolean>
26
33
  }
27
34
  >() {}
28
35
 
36
+ /**
37
+ * @since 1.0.0
38
+ * @category Constructors
39
+ */
40
+ export const make: (
41
+ options: { readonly isAlive: (address: RunnerAddress) => Effect.Effect<boolean> }
42
+ ) => Effect.Effect<
43
+ RunnerHealth["Type"],
44
+ never,
45
+ Scope.Scope
46
+ > = Effect.fnUntraced(function*(options: {
47
+ readonly isAlive: (address: RunnerAddress) => Effect.Effect<boolean>
48
+ }) {
49
+ const connections = yield* RcMap.make({
50
+ lookup: (_address: RunnerAddress) => Effect.void
51
+ })
52
+
53
+ const onConnection = (address: RunnerAddress) => RcMap.get(connections, address)
54
+ const isAlive = Effect.fnUntraced(function*(address: RunnerAddress) {
55
+ if (yield* RcMap.has(connections, address)) {
56
+ return true
57
+ }
58
+ return yield* options.isAlive(address)
59
+ })
60
+
61
+ return RunnerHealth.of({
62
+ onConnection,
63
+ isAlive
64
+ })
65
+ })
66
+
29
67
  /**
30
68
  * A layer which will **always** consider a Runner healthy.
31
69
  *
@@ -34,9 +72,9 @@ export class RunnerHealth extends Context.Tag("@effect/cluster/RunnerHealth")<
34
72
  * @since 1.0.0
35
73
  * @category layers
36
74
  */
37
- export const layerNoop = Layer.succeed(
75
+ export const layerNoop = Layer.scoped(
38
76
  RunnerHealth,
39
- RunnerHealth.of({
77
+ make({
40
78
  isAlive: () => Effect.succeed(true)
41
79
  })
42
80
  )
@@ -45,10 +83,10 @@ export const layerNoop = Layer.succeed(
45
83
  * @since 1.0.0
46
84
  * @category Constructors
47
85
  */
48
- export const make: Effect.Effect<
86
+ export const makePing: Effect.Effect<
49
87
  RunnerHealth["Type"],
50
88
  never,
51
- Runners.Runners
89
+ Runners.Runners | Scope.Scope
52
90
  > = Effect.gen(function*() {
53
91
  const runners = yield* Runners.Runners
54
92
 
@@ -60,7 +98,7 @@ export const make: Effect.Effect<
60
98
  )
61
99
  }
62
100
 
63
- return RunnerHealth.of({ isAlive })
101
+ return yield* make({ isAlive })
64
102
  })
65
103
 
66
104
  /**
@@ -73,7 +111,7 @@ export const layer: Layer.Layer<
73
111
  RunnerHealth,
74
112
  never,
75
113
  Runners.Runners
76
- > = Layer.effect(RunnerHealth, make)
114
+ > = Layer.scoped(RunnerHealth, makePing)
77
115
 
78
116
  /**
79
117
  * A layer which will ping a Runner directly to check if it is healthy.
@@ -57,7 +57,9 @@ export class ShardManager extends Context.Tag("@effect/cluster/ShardManager")<Sh
57
57
  /**
58
58
  * Get a stream of sharding events emit by the shard manager.
59
59
  */
60
- readonly shardingEvents: Effect.Effect<Queue.Dequeue<ShardingEvent>, never, Scope>
60
+ readonly shardingEvents: (
61
+ address: Option.Option<RunnerAddress>
62
+ ) => Effect.Effect<Queue.Dequeue<ShardingEvent>, never, Scope>
61
63
  /**
62
64
  * Register a new runner with the cluster.
63
65
  */
@@ -236,7 +238,9 @@ export class ShardManagerClient
236
238
  /**
237
239
  * Get a stream of sharding events emit by the shard manager.
238
240
  */
239
- readonly shardingEvents: Effect.Effect<Mailbox.ReadonlyMailbox<ShardingEvent>, never, Scope>
241
+ readonly shardingEvents: (
242
+ address: Option.Option<RunnerAddress>
243
+ ) => Effect.Effect<Mailbox.ReadonlyMailbox<ShardingEvent>, never, Scope>
240
244
  /**
241
245
  * Get the current time on the shard manager.
242
246
  */
@@ -287,6 +291,7 @@ export class Rpcs extends RpcGroup.make(
287
291
  success: Schema.Array(Schema.Tuple(ShardId, Schema.Option(RunnerAddress)))
288
292
  }),
289
293
  Rpc.make("ShardingEvents", {
294
+ payload: { address: Schema.Option(RunnerAddress) },
290
295
  success: ShardingEventSchema,
291
296
  stream: true
292
297
  }),
@@ -347,7 +352,7 @@ export const makeClientLocal = Effect.gen(function*() {
347
352
  unregister: () => Effect.void,
348
353
  notifyUnhealthyRunner: () => Effect.void,
349
354
  getAssignments: Effect.succeed(shards),
350
- shardingEvents: Effect.gen(function*() {
355
+ shardingEvents: Effect.fnUntraced(function*(_address) {
351
356
  const mailbox = yield* Mailbox.make<ShardingEvent>()
352
357
  yield* mailbox.offer(ShardingEvent.StreamStarted())
353
358
  return mailbox
@@ -379,19 +384,20 @@ export const makeClientRpc: Effect.Effect<
379
384
  unregister: (address) => Effect.orDie(client.Unregister({ address })),
380
385
  notifyUnhealthyRunner: (address) => Effect.orDie(client.NotifyUnhealthyRunner({ address })),
381
386
  getAssignments: Effect.orDie(client.GetAssignments()),
382
- shardingEvents: Mailbox.make<ShardingEvent>().pipe(
383
- Effect.tap(Effect.fnUntraced(
384
- function*(mailbox) {
385
- const events = yield* client.ShardingEvents(void 0, { asMailbox: true })
386
- const take = Effect.orDie(events.takeAll)
387
- while (true) {
388
- mailbox.unsafeOfferAll((yield* take)[0])
389
- }
390
- },
391
- (effect, mb) => Mailbox.into(effect, mb),
392
- Effect.forkScoped
393
- ))
394
- ),
387
+ shardingEvents: (address) =>
388
+ Mailbox.make<ShardingEvent>().pipe(
389
+ Effect.tap(Effect.fnUntraced(
390
+ function*(mailbox) {
391
+ const events = yield* client.ShardingEvents({ address }, { asMailbox: true })
392
+ const take = Effect.orDie(events.takeAll)
393
+ while (true) {
394
+ mailbox.unsafeOfferAll((yield* take)[0])
395
+ }
396
+ },
397
+ (effect, mb) => Mailbox.into(effect, mb),
398
+ Effect.forkScoped
399
+ ))
400
+ ),
395
401
  getTime: Effect.orDie(client.GetTime())
396
402
  })
397
403
  })
@@ -738,7 +744,11 @@ export const make = Effect.gen(function*() {
738
744
 
739
745
  return ShardManager.of({
740
746
  getAssignments,
741
- shardingEvents: PubSub.subscribe(events),
747
+ shardingEvents: (address) =>
748
+ Effect.zipRight(
749
+ Option.isSome(address) ? runnerHealthApi.onConnection(address.value) : Effect.void,
750
+ PubSub.subscribe(events)
751
+ ),
742
752
  register,
743
753
  unregister,
744
754
  rebalance,
@@ -773,8 +783,8 @@ export const layerServerHandlers = Rpcs.toLayer(Effect.gen(function*() {
773
783
  shardManager.getAssignments,
774
784
  (assignments) => Array.from(assignments)
775
785
  ),
776
- ShardingEvents: Effect.fnUntraced(function*() {
777
- const queue = yield* shardManager.shardingEvents
786
+ ShardingEvents: Effect.fnUntraced(function*({ address }) {
787
+ const queue = yield* shardManager.shardingEvents(address)
778
788
  const mailbox = yield* Mailbox.make<ShardingEvent>()
779
789
 
780
790
  yield* mailbox.offer(ShardingEvent.StreamStarted())
package/src/Sharding.ts CHANGED
@@ -829,7 +829,7 @@ const make = Effect.gen(function*() {
829
829
  yield* stopShardManagerTimeout
830
830
 
831
831
  yield* Effect.logDebug("Subscribing to sharding events")
832
- const mailbox = yield* shardManager.shardingEvents
832
+ const mailbox = yield* shardManager.shardingEvents(config.runnerAddress)
833
833
  const startedLatch = yield* Deferred.make<void>()
834
834
 
835
835
  const eventsFiber = yield* Effect.gen(function*() {