Skip to content

Commit d3dd1cd

Browse files
committed
backport effect v4 cluster
1 parent 79a612d commit d3dd1cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2076
-3750
lines changed

.changeset/loud-cows-prove.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
"@effect/platform-node-shared": minor
3+
"@effect/platform-node": minor
4+
"@effect/platform-bun": minor
5+
"@effect/cluster": minor
6+
"@effect/rpc": patch
7+
"@effect/workflow": minor
8+
---
9+
10+
backport @effect/cluster from effect v4
11+
12+
@effect/cluster no longer requires a Shard Manager, and instead relies on the
13+
`RunnerStorage` service to track runner state.
14+
15+
To migrate, remove any Shard Manager deployments and use the updated layers in
16+
`@effect/platform-node` or `@effect/platform-bun`.
17+
18+
# Breaking Changes
19+
20+
- `ShardManager` module has been removed
21+
- `@effect/platform-node/NodeClusterSocketRunner` is now
22+
`@effect/cluster/NodeClusterSocket`
23+
- `@effect/platform-node/NodeClusterHttpRunner` is now
24+
`@effect/cluster/NodeClusterHttp`
25+
- `@effect/platform-bun/BunClusterSocketRunner` is now
26+
`@effect/cluster/BunClusterSocket`
27+
- `@effect/platform-bun/BunClusterHttpRunner` is now
28+
`@effect/cluster/BunClusterHttp`
29+
30+
# New Features
31+
32+
- `RunnerHealth.layerK8s` has been added, which uses the Kubernetes API to track
33+
runner health and liveness. To use it, you will need a service account with
34+
permissions to read pod information.

.changeset/petite-signs-thank.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@effect/sql-pg": patch
3+
---
4+
5+
disable pg onnotice by default

.changeset/plenty-bats-ask.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@effect/platform": patch
3+
---
4+
5+
expose Layer output in HttpLayerRouter.serve

.changeset/warm-aliens-dig.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": minor
3+
---
4+
5+
add experimental HashRing module

packages/cluster/src/ClusterMetrics.ts

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
*/
44
import * as Metric from "effect/Metric"
55

6-
/**
7-
* @since 1.0.0
8-
* @category metrics
9-
*/
10-
export const shards = Metric.gauge("effect_cluster_shards")
11-
126
/**
137
* @since 1.0.0
148
* @category metrics
@@ -21,28 +15,30 @@ export const entities = Metric.gauge("effect_cluster_entities", {
2115
* @since 1.0.0
2216
* @category metrics
2317
*/
24-
export const singletons = Metric.gauge("effect_cluster_singletons")
25-
26-
/**
27-
* @since 1.0.0
28-
* @category metrics
29-
*/
30-
export const runners = Metric.gauge("effect_cluster_runners")
18+
export const singletons = Metric.gauge("effect_cluster_singletons", {
19+
bigint: true
20+
})
3121

3222
/**
3323
* @since 1.0.0
3424
* @category metrics
3525
*/
36-
export const assignedShards = Metric.gauge("effect_cluster_shards_assigned")
26+
export const runners = Metric.gauge("effect_cluster_runners", {
27+
bigint: true
28+
})
3729

3830
/**
3931
* @since 1.0.0
4032
* @category metrics
4133
*/
42-
export const unassignedShards = Metric.gauge("effect_cluster_shards_unassigned")
34+
export const runnersHealthy = Metric.gauge("effect_cluster_runners_healthy", {
35+
bigint: true
36+
})
4337

4438
/**
4539
* @since 1.0.0
4640
* @category metrics
4741
*/
48-
export const rebalances = Metric.counter("effect_cluster_rebalances")
42+
export const shards = Metric.gauge("effect_cluster_shards", {
43+
bigint: true
44+
})

packages/cluster/src/ClusterWorkflowEngine.ts

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22
* @since 1.0.0
33
*/
44
import * as Rpc from "@effect/rpc/Rpc"
5+
import * as RpcServer from "@effect/rpc/RpcServer"
56
import { DurableDeferred } from "@effect/workflow"
67
import * as Activity from "@effect/workflow/Activity"
78
import * as DurableClock from "@effect/workflow/DurableClock"
89
import * as Workflow from "@effect/workflow/Workflow"
910
import { WorkflowEngine, WorkflowInstance } from "@effect/workflow/WorkflowEngine"
1011
import * as Arr from "effect/Array"
12+
import * as Cause from "effect/Cause"
1113
import * as Context from "effect/Context"
1214
import * as DateTime from "effect/DateTime"
1315
import * as Duration from "effect/Duration"
1416
import * as Effect from "effect/Effect"
1517
import type * as Exit from "effect/Exit"
1618
import * as Fiber from "effect/Fiber"
19+
import * as FiberId from "effect/FiberId"
1720
import * as Layer from "effect/Layer"
1821
import * as Option from "effect/Option"
1922
import type * as ParseResult from "effect/ParseResult"
@@ -291,17 +294,17 @@ export const make = Effect.gen(function*() {
291294
) as any
292295
},
293296

294-
activity: Effect.fnUntraced(
295-
function*(request: Entity.Request<any>) {
296-
const activityId = `${executionId}/${request.payload.name}`
297+
activity(request: Entity.Request<any>) {
298+
const activityId = `${executionId}/${request.payload.name}`
299+
const instance = WorkflowInstance.initial(workflow, executionId)
300+
return Effect.gen(function*() {
297301
let entry = activities.get(activityId)
298302
while (!entry) {
299303
const latch = Effect.unsafeMakeLatch()
300304
activityLatches.set(activityId, latch)
301305
yield* latch.await
302306
entry = activities.get(activityId)
303307
}
304-
const instance = WorkflowInstance.initial(workflow, executionId)
305308
const contextMap = new Map(entry.runtime.context.unsafeMap)
306309
contextMap.set(Activity.CurrentAttempt.key, request.payload.attempt)
307310
contextMap.set(WorkflowInstance.key, instance)
@@ -311,23 +314,29 @@ export const make = Effect.gen(function*() {
311314
runtimeFlags: Runtime.defaultRuntimeFlags
312315
})
313316
return yield* entry.activity.executeEncoded.pipe(
314-
Effect.interruptible,
315-
Effect.onInterrupt(() => {
316-
instance.suspended = true
317-
return Effect.void
318-
}),
319-
Workflow.intoResult,
320-
Effect.provide(runtime),
321-
Effect.ensuring(Effect.sync(() => {
322-
activities.delete(activityId)
323-
}))
317+
Effect.provide(runtime)
324318
)
325-
},
326-
Rpc.wrap({
327-
fork: true,
328-
uninterruptible: true
329-
})
330-
),
319+
}).pipe(
320+
Workflow.intoResult,
321+
Effect.catchAllCause((cause) => {
322+
const interruptors = Cause.interruptors(cause)
323+
// we only want to store explicit interrupts
324+
const ids = Array.from(interruptors, (id) => Array.from(FiberId.ids(id))).flat()
325+
const suspend = ids.includes(RpcServer.fiberIdClientInterrupt.id) ||
326+
ids.includes(RpcServer.fiberIdTransientInterrupt.id)
327+
return suspend ? Effect.succeed(new Workflow.Suspended()) : Effect.failCause(cause)
328+
}),
329+
Effect.provideService(WorkflowInstance, instance),
330+
Effect.provideService(Activity.CurrentAttempt, request.payload.attempt),
331+
Effect.ensuring(Effect.sync(() => {
332+
activities.delete(activityId)
333+
})),
334+
Rpc.wrap({
335+
fork: true,
336+
uninterruptible: true
337+
})
338+
)
339+
},
331340

332341
deferred: Effect.fnUntraced(function*(request: Entity.Request<any>) {
333342
yield* ensureSuccess(resume(workflow, executionId))

packages/cluster/src/EntityAddress.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,13 @@ export class EntityAddress extends Schema.Class<EntityAddress>(SymbolKey)({
6363
export const EntityAddressFromSelf: Schema.Schema<EntityAddress> = Schema.typeSchema(
6464
EntityAddress
6565
)
66+
67+
/**
68+
* @since 4.0.0
69+
* @category constructors
70+
*/
71+
export const make = (options: {
72+
readonly shardId: ShardId
73+
readonly entityType: EntityType
74+
readonly entityId: EntityId
75+
}): EntityAddress => new EntityAddress(options, { disableValidation: true })

packages/cluster/src/EntityId.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,9 @@ export const EntityId = Schema.NonEmptyTrimmedString.pipe(Schema.brand("EntityId
1414
* @category models
1515
*/
1616
export type EntityId = typeof EntityId.Type
17+
18+
/**
19+
* @since 1.0.0
20+
* @category constructors
21+
*/
22+
export const make = (id: string): EntityId => id as EntityId

packages/cluster/src/HttpCommon.ts

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)