@rikalabs/akter 0.1.0-alpha.0 → 0.1.0-alpha.3

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.
Files changed (308) hide show
  1. package/CHANGELOG.md +46 -3
  2. package/README.md +2 -2
  3. package/dist/actor/definition.d.ts +13 -9
  4. package/dist/actor/descriptor.d.ts +2 -2
  5. package/dist/actor/descriptor.js +4 -4
  6. package/dist/client/calls.js +1 -1
  7. package/dist/client/index.d.ts +1 -1
  8. package/dist/client/index.js +1 -1
  9. package/dist/errors/actor.d.ts +12 -42
  10. package/dist/errors/actor.js +13 -42
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/members/payload.d.ts +1 -1
  14. package/dist/protocol/inspection.d.ts +221 -1
  15. package/dist/protocol/inspection.js +151 -2
  16. package/dist/protocol/wire.d.ts +6 -49
  17. package/dist/protocol/wire.js +1 -10
  18. package/dist/runtime/actors.d.ts +3 -0
  19. package/dist/runtime/adoption/backfill.js +1 -1
  20. package/dist/runtime/adoption/enforce.js +2 -2
  21. package/dist/runtime/adoption/observe.js +1 -1
  22. package/dist/runtime/adoption/plan.d.ts +1 -1
  23. package/dist/runtime/adoption/startup.js +1 -1
  24. package/dist/runtime/adoption/status.d.ts +1 -1
  25. package/dist/runtime/app.d.ts +65 -0
  26. package/dist/runtime/app.js +38 -0
  27. package/dist/runtime/connections/holder.d.ts +11 -1
  28. package/dist/runtime/connections/holder.js +8 -4
  29. package/dist/runtime/connections/streams.d.ts +4 -4
  30. package/dist/runtime/content/store.js +15 -11
  31. package/dist/runtime/database/bounded.d.ts +4 -18
  32. package/dist/runtime/database/bounded.js +36 -22
  33. package/dist/runtime/database/coordination.d.ts +12 -3
  34. package/dist/runtime/database/coordination.js +29 -36
  35. package/dist/runtime/database/migrations.d.ts +61 -29
  36. package/dist/runtime/database/migrations.js +375 -139
  37. package/dist/runtime/database/replica.d.ts +4 -1
  38. package/dist/runtime/database/replica.js +4 -1
  39. package/dist/runtime/database/schema.d.ts +13 -0
  40. package/dist/runtime/database/schema.js +13 -0
  41. package/dist/runtime/database/shards.d.ts +31 -13
  42. package/dist/runtime/database/shards.js +38 -26
  43. package/dist/runtime/entity/register.d.ts +8 -1
  44. package/dist/runtime/entity/register.js +58 -7
  45. package/dist/runtime/fleet/checks.js +4 -4
  46. package/dist/runtime/fleet/maintainer.d.ts +1 -1
  47. package/dist/runtime/fleet/maintainer.js +1 -1
  48. package/dist/runtime/index.d.ts +2 -0
  49. package/dist/runtime/index.js +1 -0
  50. package/dist/runtime/inspector/layer.d.ts +20 -0
  51. package/dist/runtime/inspector/layer.js +224 -5
  52. package/dist/runtime/inspector/queries.d.ts +54 -8
  53. package/dist/runtime/inspector/queries.js +84 -15
  54. package/dist/runtime/layer.d.ts +48 -39
  55. package/dist/runtime/layer.js +124 -56
  56. package/dist/runtime/operators/audit.d.ts +3 -0
  57. package/dist/runtime/operators/audit.js +6 -2
  58. package/dist/runtime/operators/repair.js +30 -10
  59. package/dist/runtime/operators/seed.js +4 -2
  60. package/dist/runtime/payloads/versions.d.ts +4 -4
  61. package/dist/runtime/payloads/versions.js +24 -15
  62. package/dist/runtime/queries.js +4 -2
  63. package/dist/runtime/registration.d.ts +5 -2
  64. package/dist/runtime/registration.js +3 -3
  65. package/dist/runtime/runner.d.ts +12 -0
  66. package/dist/runtime/runner.js +12 -0
  67. package/dist/runtime/storage/codec.d.ts +19 -7
  68. package/dist/runtime/storage/codec.js +23 -7
  69. package/dist/runtime/storage/placements.d.ts +6 -1
  70. package/dist/runtime/storage/placements.js +98 -6
  71. package/dist/runtime/storage/retention.d.ts +6 -0
  72. package/dist/runtime/storage/retention.js +25 -13
  73. package/dist/runtime/subscriptions/relay.js +47 -44
  74. package/dist/runtime/subscriptions/storage.d.ts +3 -2
  75. package/dist/runtime/subscriptions/storage.js +9 -6
  76. package/dist/runtime/telemetry/live.d.ts +255 -0
  77. package/dist/runtime/telemetry/live.js +540 -0
  78. package/dist/runtime/telemetry/metrics.d.ts +2 -0
  79. package/dist/runtime/telemetry/metrics.js +4 -1
  80. package/dist/runtime/telemetry/sampler.js +33 -13
  81. package/dist/runtime/telemetry/spans.d.ts +1 -1
  82. package/dist/runtime/telemetry/spans.js +1 -1
  83. package/dist/runtime/topology/locks.d.ts +6 -3
  84. package/dist/runtime/topology/locks.js +27 -4
  85. package/dist/runtime/turn/execute.d.ts +2 -0
  86. package/dist/runtime/turn/execute.js +5 -2
  87. package/dist/runtime/turn/pipeline.d.ts +5 -12
  88. package/dist/runtime/turn/pipeline.js +11 -11
  89. package/dist/runtime/turn/relay.d.ts +13 -3
  90. package/dist/runtime/turn/relay.js +27 -14
  91. package/dist/runtime/turn/rows.js +4 -4
  92. package/dist/runtime/workflows/compatibility.d.ts +1 -1
  93. package/dist/runtime/workflows/compatibility.js +85 -31
  94. package/dist/runtime/workflows/engine.js +20 -17
  95. package/dist/serve/layer.js +3 -2
  96. package/dist/tables/owned.d.ts +1 -1
  97. package/dist/tables/owned.js +1 -1
  98. package/dist/testing/actor-test.d.ts +2 -24
  99. package/dist/testing/actor-test.js +1 -27
  100. package/dist/testing/index.d.ts +0 -12
  101. package/dist/testing/index.js +0 -6
  102. package/package.json +1 -1
  103. package/dist/runtime/database/neki/migrations.d.ts +0 -31
  104. package/dist/runtime/database/neki/migrations.js +0 -276
  105. package/dist/runtime/database/neki/session.d.ts +0 -23
  106. package/dist/runtime/database/neki/session.js +0 -31
  107. package/dist/testing/cluster.d.ts +0 -93
  108. package/dist/testing/cluster.js +0 -296
  109. package/dist/testing/conformance/access.d.ts +0 -5
  110. package/dist/testing/conformance/access.js +0 -531
  111. package/dist/testing/conformance/admission.d.ts +0 -11
  112. package/dist/testing/conformance/admission.js +0 -182
  113. package/dist/testing/conformance/adoption.d.ts +0 -2
  114. package/dist/testing/conformance/adoption.js +0 -1019
  115. package/dist/testing/conformance/assertions.d.ts +0 -202
  116. package/dist/testing/conformance/assertions.js +0 -849
  117. package/dist/testing/conformance/batches.d.ts +0 -41
  118. package/dist/testing/conformance/batches.js +0 -388
  119. package/dist/testing/conformance/blobs.d.ts +0 -14
  120. package/dist/testing/conformance/blobs.js +0 -405
  121. package/dist/testing/conformance/capacity.d.ts +0 -8
  122. package/dist/testing/conformance/capacity.js +0 -433
  123. package/dist/testing/conformance/client.d.ts +0 -5
  124. package/dist/testing/conformance/client.js +0 -719
  125. package/dist/testing/conformance/cold-serve.d.ts +0 -16
  126. package/dist/testing/conformance/cold-serve.js +0 -254
  127. package/dist/testing/conformance/connections/actors.d.ts +0 -1143
  128. package/dist/testing/conformance/connections/actors.js +0 -180
  129. package/dist/testing/conformance/connections/harness.d.ts +0 -1754
  130. package/dist/testing/conformance/connections/harness.js +0 -142
  131. package/dist/testing/conformance/connections/holders.d.ts +0 -4
  132. package/dist/testing/conformance/connections/holders.js +0 -165
  133. package/dist/testing/conformance/connections/lifecycle.d.ts +0 -4
  134. package/dist/testing/conformance/connections/lifecycle.js +0 -113
  135. package/dist/testing/conformance/connections/limits.d.ts +0 -4
  136. package/dist/testing/conformance/connections/limits.js +0 -127
  137. package/dist/testing/conformance/connections/reauthorization.d.ts +0 -4
  138. package/dist/testing/conformance/connections/reauthorization.js +0 -170
  139. package/dist/testing/conformance/connections/resync.d.ts +0 -4
  140. package/dist/testing/conformance/connections/resync.js +0 -360
  141. package/dist/testing/conformance/connections/takeover.d.ts +0 -4
  142. package/dist/testing/conformance/connections/takeover.js +0 -287
  143. package/dist/testing/conformance/connections.d.ts +0 -4
  144. package/dist/testing/conformance/connections.js +0 -15
  145. package/dist/testing/conformance/content-blobs.d.ts +0 -16
  146. package/dist/testing/conformance/content-blobs.js +0 -534
  147. package/dist/testing/conformance/counter.d.ts +0 -16
  148. package/dist/testing/conformance/counter.js +0 -813
  149. package/dist/testing/conformance/cron.d.ts +0 -5
  150. package/dist/testing/conformance/cron.js +0 -665
  151. package/dist/testing/conformance/drain.d.ts +0 -26
  152. package/dist/testing/conformance/drain.js +0 -540
  153. package/dist/testing/conformance/effect-control.d.ts +0 -38
  154. package/dist/testing/conformance/effect-control.js +0 -1059
  155. package/dist/testing/conformance/effects.d.ts +0 -23
  156. package/dist/testing/conformance/effects.js +0 -432
  157. package/dist/testing/conformance/events.d.ts +0 -28
  158. package/dist/testing/conformance/events.js +0 -335
  159. package/dist/testing/conformance/export.d.ts +0 -2
  160. package/dist/testing/conformance/export.js +0 -368
  161. package/dist/testing/conformance/fleet.d.ts +0 -444
  162. package/dist/testing/conformance/fleet.js +0 -1009
  163. package/dist/testing/conformance/groups.d.ts +0 -7
  164. package/dist/testing/conformance/groups.js +0 -353
  165. package/dist/testing/conformance/heap.d.ts +0 -3
  166. package/dist/testing/conformance/heap.js +0 -149
  167. package/dist/testing/conformance/http.d.ts +0 -2809
  168. package/dist/testing/conformance/http.js +0 -1234
  169. package/dist/testing/conformance/inspection-views.d.ts +0 -8
  170. package/dist/testing/conformance/inspection-views.js +0 -272
  171. package/dist/testing/conformance/inspector.d.ts +0 -7
  172. package/dist/testing/conformance/inspector.js +0 -650
  173. package/dist/testing/conformance/mint.d.ts +0 -58
  174. package/dist/testing/conformance/mint.js +0 -692
  175. package/dist/testing/conformance/multi-runner.d.ts +0 -8
  176. package/dist/testing/conformance/multi-runner.js +0 -403
  177. package/dist/testing/conformance/neki/plan.d.ts +0 -19
  178. package/dist/testing/conformance/neki/plan.js +0 -30
  179. package/dist/testing/conformance/observability.d.ts +0 -3
  180. package/dist/testing/conformance/observability.js +0 -343
  181. package/dist/testing/conformance/offline.d.ts +0 -4
  182. package/dist/testing/conformance/offline.js +0 -474
  183. package/dist/testing/conformance/operator-harness.d.ts +0 -57
  184. package/dist/testing/conformance/operator-harness.js +0 -78
  185. package/dist/testing/conformance/operator.d.ts +0 -3
  186. package/dist/testing/conformance/operator.js +0 -379
  187. package/dist/testing/conformance/outbox-cross-shard.d.ts +0 -14
  188. package/dist/testing/conformance/outbox-cross-shard.js +0 -160
  189. package/dist/testing/conformance/outbox.d.ts +0 -36
  190. package/dist/testing/conformance/outbox.js +0 -437
  191. package/dist/testing/conformance/payload-migrations.d.ts +0 -3
  192. package/dist/testing/conformance/payload-migrations.js +0 -612
  193. package/dist/testing/conformance/pipeline.d.ts +0 -3
  194. package/dist/testing/conformance/pipeline.js +0 -1040
  195. package/dist/testing/conformance/placement.d.ts +0 -22
  196. package/dist/testing/conformance/placement.js +0 -539
  197. package/dist/testing/conformance/platform.d.ts +0 -40
  198. package/dist/testing/conformance/platform.js +0 -101
  199. package/dist/testing/conformance/progress.d.ts +0 -39
  200. package/dist/testing/conformance/progress.js +0 -666
  201. package/dist/testing/conformance/properties.d.ts +0 -6
  202. package/dist/testing/conformance/properties.js +0 -295
  203. package/dist/testing/conformance/protocols.d.ts +0 -4
  204. package/dist/testing/conformance/protocols.js +0 -618
  205. package/dist/testing/conformance/provider/advertise.d.ts +0 -21
  206. package/dist/testing/conformance/provider/advertise.js +0 -44
  207. package/dist/testing/conformance/read-your-writes.d.ts +0 -20
  208. package/dist/testing/conformance/read-your-writes.js +0 -192
  209. package/dist/testing/conformance/reducers.d.ts +0 -8
  210. package/dist/testing/conformance/reducers.js +0 -258
  211. package/dist/testing/conformance/relay.d.ts +0 -42
  212. package/dist/testing/conformance/relay.js +0 -1115
  213. package/dist/testing/conformance/restore.d.ts +0 -43
  214. package/dist/testing/conformance/restore.js +0 -341
  215. package/dist/testing/conformance/retention.d.ts +0 -14
  216. package/dist/testing/conformance/retention.js +0 -463
  217. package/dist/testing/conformance/rls.d.ts +0 -24
  218. package/dist/testing/conformance/rls.js +0 -576
  219. package/dist/testing/conformance/simulation.d.ts +0 -31
  220. package/dist/testing/conformance/simulation.js +0 -167
  221. package/dist/testing/conformance/single-shard.d.ts +0 -2
  222. package/dist/testing/conformance/single-shard.js +0 -125
  223. package/dist/testing/conformance/singleton.d.ts +0 -3
  224. package/dist/testing/conformance/singleton.js +0 -293
  225. package/dist/testing/conformance/statements.d.ts +0 -60
  226. package/dist/testing/conformance/statements.js +0 -108
  227. package/dist/testing/conformance/streams.d.ts +0 -7
  228. package/dist/testing/conformance/streams.js +0 -280
  229. package/dist/testing/conformance/subscriptions/access.d.ts +0 -4
  230. package/dist/testing/conformance/subscriptions/access.js +0 -98
  231. package/dist/testing/conformance/subscriptions/actors.d.ts +0 -4910
  232. package/dist/testing/conformance/subscriptions/actors.js +0 -372
  233. package/dist/testing/conformance/subscriptions/cluster.d.ts +0 -4
  234. package/dist/testing/conformance/subscriptions/cluster.js +0 -89
  235. package/dist/testing/conformance/subscriptions/delivery.d.ts +0 -4
  236. package/dist/testing/conformance/subscriptions/delivery.js +0 -253
  237. package/dist/testing/conformance/subscriptions/deploys.d.ts +0 -4
  238. package/dist/testing/conformance/subscriptions/deploys.js +0 -162
  239. package/dist/testing/conformance/subscriptions/epochs.d.ts +0 -4
  240. package/dist/testing/conformance/subscriptions/epochs.js +0 -169
  241. package/dist/testing/conformance/subscriptions/failures.d.ts +0 -4
  242. package/dist/testing/conformance/subscriptions/failures.js +0 -108
  243. package/dist/testing/conformance/subscriptions/feeds.d.ts +0 -4
  244. package/dist/testing/conformance/subscriptions/feeds.js +0 -218
  245. package/dist/testing/conformance/subscriptions/harness.d.ts +0 -124
  246. package/dist/testing/conformance/subscriptions/harness.js +0 -143
  247. package/dist/testing/conformance/subscriptions/operator.d.ts +0 -4
  248. package/dist/testing/conformance/subscriptions/operator.js +0 -128
  249. package/dist/testing/conformance/subscriptions/retention.d.ts +0 -4
  250. package/dist/testing/conformance/subscriptions/retention.js +0 -288
  251. package/dist/testing/conformance/subscriptions/routing.d.ts +0 -4
  252. package/dist/testing/conformance/subscriptions/routing.js +0 -179
  253. package/dist/testing/conformance/subscriptions.d.ts +0 -4
  254. package/dist/testing/conformance/subscriptions.js +0 -19
  255. package/dist/testing/conformance/tables.d.ts +0 -125
  256. package/dist/testing/conformance/tables.js +0 -664
  257. package/dist/testing/conformance/transports/actors.d.ts +0 -1907
  258. package/dist/testing/conformance/transports/actors.js +0 -163
  259. package/dist/testing/conformance/transports/client.d.ts +0 -3
  260. package/dist/testing/conformance/transports/client.js +0 -237
  261. package/dist/testing/conformance/transports/feeds.d.ts +0 -3
  262. package/dist/testing/conformance/transports/feeds.js +0 -232
  263. package/dist/testing/conformance/transports/harness.d.ts +0 -93
  264. package/dist/testing/conformance/transports/harness.js +0 -84
  265. package/dist/testing/conformance/transports/streams.d.ts +0 -3
  266. package/dist/testing/conformance/transports/streams.js +0 -96
  267. package/dist/testing/conformance/transports/websocket.d.ts +0 -3
  268. package/dist/testing/conformance/transports/websocket.js +0 -384
  269. package/dist/testing/conformance/transports/wire.d.ts +0 -141
  270. package/dist/testing/conformance/transports/wire.js +0 -204
  271. package/dist/testing/conformance/transports.d.ts +0 -3
  272. package/dist/testing/conformance/transports.js +0 -11
  273. package/dist/testing/conformance/watch.d.ts +0 -59
  274. package/dist/testing/conformance/watch.js +0 -879
  275. package/dist/testing/conformance/workflow-engine.d.ts +0 -97
  276. package/dist/testing/conformance/workflow-engine.js +0 -253
  277. package/dist/testing/conformance/workflow-versions.d.ts +0 -3
  278. package/dist/testing/conformance/workflow-versions.js +0 -545
  279. package/dist/testing/conformance/workflows/access.d.ts +0 -4
  280. package/dist/testing/conformance/workflows/access.js +0 -147
  281. package/dist/testing/conformance/workflows/actors.d.ts +0 -2317
  282. package/dist/testing/conformance/workflows/actors.js +0 -305
  283. package/dist/testing/conformance/workflows/basics.d.ts +0 -4
  284. package/dist/testing/conformance/workflows/basics.js +0 -144
  285. package/dist/testing/conformance/workflows/engine.d.ts +0 -4
  286. package/dist/testing/conformance/workflows/engine.js +0 -80
  287. package/dist/testing/conformance/workflows/guards.d.ts +0 -4
  288. package/dist/testing/conformance/workflows/guards.js +0 -172
  289. package/dist/testing/conformance/workflows/harness.d.ts +0 -14
  290. package/dist/testing/conformance/workflows/harness.js +0 -44
  291. package/dist/testing/conformance/workflows/recovery.d.ts +0 -4
  292. package/dist/testing/conformance/workflows/recovery.js +0 -181
  293. package/dist/testing/conformance/workflows/starts.d.ts +0 -4
  294. package/dist/testing/conformance/workflows/starts.js +0 -57
  295. package/dist/testing/conformance/workflows/suspension.d.ts +0 -4
  296. package/dist/testing/conformance/workflows/suspension.js +0 -106
  297. package/dist/testing/conformance/workflows/waits.d.ts +0 -4
  298. package/dist/testing/conformance/workflows/waits.js +0 -284
  299. package/dist/testing/conformance/workflows.d.ts +0 -4
  300. package/dist/testing/conformance/workflows.js +0 -19
  301. package/dist/testing/conformance.d.ts +0 -330
  302. package/dist/testing/conformance.js +0 -364
  303. package/dist/testing/foundation.d.ts +0 -41
  304. package/dist/testing/foundation.js +0 -517
  305. package/dist/testing/simulate-cluster.d.ts +0 -112
  306. package/dist/testing/simulate-cluster.js +0 -257
  307. package/dist/testing/simulate.d.ts +0 -90
  308. package/dist/testing/simulate.js +0 -127
@@ -1,437 +0,0 @@
1
- import { Cause, Data, DateTime, Duration, Effect, Exit, Fiber, Layer, Schema } from "effect";
2
- import { SqlClient } from "effect/sql";
3
- import { Actor, Caller, Intent, System } from "../../index.js";
4
- import { CommandId } from "../../identity/command.js";
5
- import { claimIntents } from "../../runtime/turn/relay.js";
6
- import { ActorTest } from "../actor-test.js";
7
- export const outboxFixture = () => ({
8
- receives: 0,
9
- failNext: false,
10
- escaped: Effect.void,
11
- });
12
- const Delivery = Schema.Struct({ body: Schema.String, commandId: Schema.String, caller: Caller });
13
- const InboxLog = Schema.Struct({ log: Schema.optional(Schema.Array(Delivery)) });
14
- const Receive = Actor.command("Receive", { payload: Schema.String });
15
- const Touch = Actor.command("Touch");
16
- const Inbox = Actor.make("Inbox", {
17
- key: Schema.String,
18
- state: Actor.state({
19
- log: Schema.Array(Delivery).pipe(Schema.withDecodingDefault(Effect.succeed([]))),
20
- }),
21
- api: { Touch },
22
- internal: { Receive },
23
- });
24
- class Refused extends Schema.TaggedError()("Refused", {}) {
25
- }
26
- const Message = Schema.Struct({ to: Schema.String, body: Schema.String });
27
- const Send = Actor.command("Send", { payload: Message });
28
- const SendThenRefuse = Actor.command("SendThenRefuse", { payload: Message, error: Refused });
29
- const SendThenDie = Actor.command("SendThenDie", { payload: Message });
30
- const Schedule = Actor.command("Schedule", {
31
- payload: Schema.Struct({
32
- ...Message.fields,
33
- afterMs: Schema.optional(Schema.Int),
34
- atMs: Schema.optional(Schema.Int),
35
- key: Schema.optional(Schema.String),
36
- }),
37
- });
38
- const Cancel = Actor.command("Cancel", { payload: Schema.String });
39
- const CancelThenRefuse = Actor.command("CancelThenRefuse", {
40
- payload: Schema.String,
41
- error: Refused,
42
- });
43
- const Escape = Actor.command("Escape", { payload: Schema.String });
44
- const Steal = Actor.command("Steal");
45
- /** @internal */
46
- export const Outboxer = Actor.make("Outboxer", {
47
- key: Schema.String,
48
- api: { Send, SendThenRefuse, SendThenDie, Schedule, Cancel, CancelThenRefuse, Escape, Steal },
49
- });
50
- const Post = Actor.command("Post");
51
- const Archive = Actor.command("Archive");
52
- const IdleCheck = Actor.command("IdleCheck");
53
- const Room = Actor.make("Room", {
54
- key: Schema.String,
55
- state: Actor.state({
56
- closed: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
57
- }),
58
- api: { Post, Archive },
59
- internal: { IdleCheck },
60
- });
61
- export const outboxLayer = (fixture) => Layer.mergeAll(Inbox.toLayer(Effect.succeed({
62
- Touch: () => Effect.void,
63
- Receive: Effect.fnUntraced(function* (body) {
64
- const turn = yield* Inbox.Turn;
65
- fixture.receives += 1;
66
- if (fixture.failNext) {
67
- fixture.failNext = false;
68
- return yield* Effect.die(new Error("Receiver defect"));
69
- }
70
- yield* turn.state.set({
71
- log: [...turn.state.log, { body, commandId: turn.commandId, caller: turn.caller }],
72
- });
73
- }),
74
- })), Outboxer.toLayer(Effect.succeed({
75
- Send: Effect.fnUntraced(function* ({ to, body }) {
76
- yield* (yield* Inbox.intents(to)).Receive(body);
77
- }),
78
- SendThenRefuse: Effect.fnUntraced(function* ({ to, body }) {
79
- yield* (yield* Inbox.intents(to)).Receive(body);
80
- return yield* Refused.make({});
81
- }),
82
- SendThenDie: Effect.fnUntraced(function* ({ to, body }) {
83
- yield* (yield* Inbox.intents(to)).Receive(body);
84
- return yield* Effect.die(new Error("Sender defect after staging"));
85
- }),
86
- Schedule: Effect.fnUntraced(function* ({ to, body, afterMs, atMs, key }) {
87
- let intent = (yield* Inbox.intents(to)).Receive(body);
88
- if (afterMs !== undefined)
89
- intent = intent.pipe(Intent.after(Duration.millis(afterMs)));
90
- if (atMs !== undefined)
91
- intent = intent.pipe(Intent.at(DateTime.makeUnsafe(atMs)));
92
- if (key !== undefined)
93
- intent = intent.pipe(Intent.key(key));
94
- yield* intent;
95
- }),
96
- Cancel: (key) => Intent.cancel(key),
97
- CancelThenRefuse: Effect.fnUntraced(function* (key) {
98
- yield* Intent.cancel(key);
99
- return yield* Refused.make({});
100
- }),
101
- Escape: Effect.fnUntraced(function* (to) {
102
- fixture.escaped = (yield* Inbox.intents(to)).Receive("escaped");
103
- }),
104
- Steal: () => Effect.suspend(() => fixture.escaped),
105
- })), Room.toLayer(Effect.succeed({
106
- Post: Effect.fnUntraced(function* () {
107
- const turn = yield* Room.Turn;
108
- const self = yield* Room.intents(turn.id);
109
- yield* self.IdleCheck().pipe(Intent.after("24 hours"), Intent.key("idle"));
110
- }),
111
- Archive: Effect.fnUntraced(function* () {
112
- const turn = yield* Room.Turn;
113
- yield* turn.state.set({ closed: true });
114
- yield* Intent.cancel("idle");
115
- }),
116
- IdleCheck: Effect.fnUntraced(function* () {
117
- const self = yield* Room.intents((yield* Room.Turn).id);
118
- yield* self.Archive();
119
- }),
120
- })));
121
- const inboxLog = Effect.fnUntraced(function* (to) {
122
- const inbox = yield* Inbox.get(to);
123
- const { state } = yield* (yield* ActorTest).inspect(inbox.ref);
124
- return (yield* Schema.decodeUnknownEffect(InboxLog)(state).pipe(Effect.orDie)).log ?? [];
125
- });
126
- export const receivedBodies = (to) => inboxLog(to).pipe(Effect.map((log) => log.map(({ body }) => body)));
127
- export const PlanNode = Schema.Struct({
128
- "Node Type": Schema.String,
129
- "Relation Name": Schema.optional(Schema.String),
130
- "Index Name": Schema.optional(Schema.String),
131
- "Actual Rows": Schema.Finite,
132
- "Shared Hit Blocks": Schema.Finite,
133
- "Shared Read Blocks": Schema.Finite,
134
- "Rows Removed by Filter": Schema.optional(Schema.Finite),
135
- Plans: Schema.optional(Schema.Array(Schema.suspend(() => PlanNode))),
136
- });
137
- export const ExplainOutput = Schema.Tuple([Schema.Struct({ Plan: PlanNode })]);
138
- const explainScan = Effect.fnUntraced(function* (now) {
139
- const sql = yield* SqlClient.SqlClient;
140
- const [text, parameters] = claimIntents({
141
- sql,
142
- now,
143
- limit: 16,
144
- leaseMs: 37_000,
145
- maxBackoffMs: 256_000,
146
- }).compile();
147
- const [row] = yield* sql.unsafe(`EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) ${text}`, parameters);
148
- const [output] = yield* Schema.decodeUnknownEffect(ExplainOutput)(row?.["QUERY PLAN"]).pipe(Effect.orDie);
149
- return output.Plan;
150
- });
151
- export const planNodes = (node) => [
152
- node,
153
- ...(node.Plans ?? []).flatMap(planNodes),
154
- ];
155
- const seedSleepers = Effect.fnUntraced(function* (from, to, dueAt) {
156
- const sql = yield* SqlClient.SqlClient;
157
- yield* sql `INSERT INTO actor_generations (routing_key, tenant_id, actor_type, actor_id)
158
- SELECT ((i % 256) - 128)::bigint << 56 | i, 'scan', 'Sleeper', i::text
159
- FROM generate_series(${from}::int, ${to}::int) AS i`;
160
- yield* sql `ANALYZE actor_generations`;
161
- yield* sql `INSERT INTO actor_outbox (routing_key, intent_id, bucket, due_at_ms,
162
- scheduled_at_ms, tenant_id, actor_type, actor_id, target_type, target_id, command, payload,
163
- caller)
164
- SELECT ((i % 256) - 128)::bigint << 56 | i, 'sleep-' || i, (i % 256) - 128, ${dueAt}::bigint,
165
- ${dueAt}::bigint, 'scan', 'Sleeper', i::text, 'Sleeper', i::text, 'Wake', '{}', '{}'
166
- FROM generate_series(${from}::int, ${to}::int) AS i`;
167
- yield* sql `ANALYZE actor_outbox`;
168
- });
169
- const measureScan = Effect.fnUntraced(function* (now) {
170
- const root = yield* explainScan(now);
171
- const outbox = planNodes(root).filter((node) => node["Relation Name"] === "actor_outbox" || node["Index Name"]?.startsWith("actor_outbox"));
172
- return {
173
- seqScans: outbox.filter((node) => node["Node Type"] === "Seq Scan").length,
174
- indexes: [...new Set(outbox.flatMap((node) => node["Index Name"] ?? []))],
175
- rows: root["Actual Rows"],
176
- indexRows: outbox
177
- .filter((node) => node["Index Name"] === "actor_outbox_due_kind")
178
- .reduce((total, node) => total + node["Actual Rows"], 0),
179
- blocks: root["Shared Hit Blocks"] + root["Shared Read Blocks"],
180
- };
181
- });
182
- class Measured extends Data.TaggedError("Measured") {
183
- }
184
- /** The default claim lease for these actors: 30 s `commandTimeout` + 2 s `lockWait` + 5 s. */
185
- export const CLAIM_LEASE = "37 seconds";
186
- /** Outbox cases: committed intents deliver as System commands under the intent id, and staged intents from failed or rolled-back turns never deliver. */
187
- export const outboxConformance = [
188
- {
189
- name: "delivers a committed intent as a System command whose command id is the intent id",
190
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
191
- const test = yield* ActorTest;
192
- const sender = yield* Outboxer.get("deliver");
193
- yield* sender.Send({ to: "deliver-inbox", body: "hello" });
194
- yield* test.advance(0);
195
- const inbox = yield* Inbox.get("deliver-inbox");
196
- const [delivery] = yield* inboxLog("deliver-inbox");
197
- expect(delivery?.body).toBe("hello");
198
- expect(Schema.is(CommandId)(delivery?.commandId)).toBe(true);
199
- expect(delivery?.caller).toEqual(System.make({ source: "actor", ref: sender.ref, onBehalfOf: { subject: "alice" } }));
200
- expect(yield* test.receiptsFor(inbox.ref, "Receive")).toBe(1);
201
- expect(yield* test.inspect(sender.ref)).toMatchObject({ receipts: 1, outbox: 0 });
202
- })),
203
- },
204
- {
205
- name: "never delivers intents from a declared failure or a rolled-back turn",
206
- run: ({ expect, environment, fixture }) => environment.run(Effect.gen(function* () {
207
- const test = yield* ActorTest;
208
- const sender = yield* Outboxer.get("rollback");
209
- const before = fixture.receives;
210
- expect(yield* sender
211
- .SendThenRefuse({ to: "rollback-inbox", body: "refused" })
212
- .pipe(Effect.flip)).toBeInstanceOf(Refused);
213
- const died = yield* sender
214
- .SendThenDie({ to: "rollback-inbox", body: "died" })
215
- .pipe(Effect.exit);
216
- expect(Exit.isFailure(died) && Cause.pretty(died.cause)).toContain("Sender defect");
217
- yield* test.crashNext("beforeCommit");
218
- yield* sender.Send({ to: "rollback-inbox", body: "retried" });
219
- yield* test.advance(0);
220
- expect(yield* receivedBodies("rollback-inbox")).toEqual(["retried"]);
221
- expect(fixture.receives - before).toBe(1);
222
- expect(yield* test.inspect(sender.ref)).toMatchObject({ receipts: 2, outbox: 0 });
223
- })),
224
- },
225
- {
226
- name: "keeps a staged intent invisible and undelivered until its turn commits",
227
- requiresIndependentConnections: true,
228
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
229
- const test = yield* ActorTest;
230
- const sender = yield* Outboxer.get("visibility");
231
- const pause = yield* test.pauseNext("beforeCommit");
232
- const waiter = yield* sender
233
- .Send({ to: "visibility-inbox", body: "later" })
234
- .pipe(Effect.forkChild);
235
- yield* pause.reached;
236
- yield* test.advance(0);
237
- expect(yield* test.inspect(sender.ref)).toMatchObject({ receipts: 0, outbox: 0 });
238
- expect(yield* receivedBodies("visibility-inbox")).toEqual([]);
239
- yield* pause.release;
240
- yield* Fiber.join(waiter);
241
- yield* test.advance(0);
242
- expect(yield* receivedBodies("visibility-inbox")).toEqual(["later"]);
243
- })),
244
- },
245
- {
246
- name: "delays timers until due, past the retry window and after caller revocation",
247
- run: ({ expect, environment, access }) => environment.run(Effect.gen(function* () {
248
- const test = yield* ActorTest;
249
- const sender = yield* Outboxer.get("timers");
250
- const now = DateTime.toEpochMillis(yield* test.now);
251
- yield* sender.Schedule({ to: "timers-inbox", body: "after", afterMs: 3_600_000 });
252
- yield* sender.Schedule({ to: "timers-inbox", body: "at", atMs: now + 7_200_000 });
253
- yield* test.advance(0);
254
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 2 });
255
- yield* test.advance("59 minutes");
256
- expect(yield* receivedBodies("timers-inbox")).toEqual([]);
257
- access.allowed = false;
258
- yield* test
259
- .advance("1 minute")
260
- .pipe(Effect.ensuring(Effect.sync(() => (access.allowed = true))));
261
- expect(yield* receivedBodies("timers-inbox")).toEqual(["after"]);
262
- yield* test.advance("1 hour");
263
- expect(yield* receivedBodies("timers-inbox")).toEqual(["after", "at"]);
264
- expect((yield* inboxLog("timers-inbox")).map(({ caller }) => caller)).toMatchObject([
265
- { source: "timer" },
266
- { source: "timer" },
267
- ]);
268
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 0 });
269
- })),
270
- },
271
- {
272
- name: "replaces a pending keyed timer and cancels it in the same transaction",
273
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
274
- const test = yield* ActorTest;
275
- const sender = yield* Outboxer.get("keyed");
276
- const to = "keyed-inbox";
277
- yield* sender.Schedule({ to, body: "first", afterMs: 3_600_000, key: "k" });
278
- yield* sender.Schedule({ to, body: "second", afterMs: 7_200_000, key: "k" });
279
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 1 });
280
- yield* test.advance("1 hour");
281
- expect(yield* receivedBodies(to)).toEqual([]);
282
- yield* test.advance("1 hour");
283
- expect(yield* receivedBodies(to)).toEqual(["second"]);
284
- yield* sender.Schedule({ to, body: "cancelled", afterMs: 60_000, key: "k" });
285
- expect(yield* sender.CancelThenRefuse("k").pipe(Effect.flip)).toBeInstanceOf(Refused);
286
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 1 });
287
- yield* sender.Cancel("k");
288
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 0 });
289
- yield* test.advance("1 hour");
290
- expect(yield* receivedBodies(to)).toEqual(["second"]);
291
- })),
292
- },
293
- {
294
- name: "pushes back the idle timer and archives once across crashes after the receiver commits",
295
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
296
- const test = yield* ActorTest;
297
- const room = yield* Room.get("r2");
298
- yield* room.Post();
299
- yield* test.advance("23 hours");
300
- yield* room.Post();
301
- yield* test.advance("23 hours");
302
- expect(yield* test.inspect(room.ref)).toMatchObject({ receipts: 2, outbox: 1 });
303
- expect((yield* test.inspect(room.ref)).state).toEqual({});
304
- yield* test.crashNext("afterCommit");
305
- yield* test.crashNext("beforeOutboxDelete");
306
- yield* test.advance("1 hour");
307
- expect(yield* test.inspect(room.ref)).toMatchObject({
308
- state: { closed: true },
309
- outbox: 0,
310
- });
311
- expect(yield* test.receiptsFor(room.ref, "IdleCheck")).toBe(1);
312
- expect(yield* test.receiptsFor(room.ref, "Archive")).toBe(1);
313
- })),
314
- },
315
- {
316
- name: "redelivers after a relay crash before outbox row deletion with one receiver transition",
317
- run: ({ expect, environment, fixture }) => environment.run(Effect.gen(function* () {
318
- const test = yield* ActorTest;
319
- const sender = yield* Outboxer.get("relay-crash");
320
- const inbox = yield* Inbox.get("relay-crash-inbox");
321
- const before = fixture.receives;
322
- yield* sender.Schedule({ to: "relay-crash-inbox", body: "once", afterMs: 60_000 });
323
- yield* test.crashNext("beforeOutboxDelete");
324
- const pause = yield* test.pauseNext("beforeOutboxDelete");
325
- yield* test.advance("1 minute");
326
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 1 });
327
- const draining = yield* test.advance(CLAIM_LEASE).pipe(Effect.forkChild);
328
- yield* pause.reached;
329
- expect(fixture.receives - before).toBe(1);
330
- expect(yield* test.receiptsFor(inbox.ref, "Receive")).toBe(1);
331
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 1 });
332
- yield* pause.release;
333
- yield* Fiber.join(draining);
334
- expect(yield* receivedBodies("relay-crash-inbox")).toEqual(["once"]);
335
- expect(fixture.receives - before).toBe(1);
336
- expect(yield* test.receiptsFor(inbox.ref, "Receive")).toBe(1);
337
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 0 });
338
- })),
339
- },
340
- {
341
- name: "rolls back a relay-delivered turn that crashes before commit and delivers it once",
342
- run: ({ expect, environment, fixture }) => environment.run(Effect.gen(function* () {
343
- const test = yield* ActorTest;
344
- const sender = yield* Outboxer.get("receiver-crash");
345
- const inbox = yield* Inbox.get("receiver-crash-inbox");
346
- const before = fixture.receives;
347
- yield* sender.Schedule({ to: "receiver-crash-inbox", body: "once", afterMs: 60_000 });
348
- yield* test.crashNext("beforeCommit");
349
- yield* test.advance("1 minute");
350
- expect(fixture.receives - before).toBe(2);
351
- expect(yield* receivedBodies("receiver-crash-inbox")).toEqual(["once"]);
352
- expect(yield* test.receiptsFor(inbox.ref, "Receive")).toBe(1);
353
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 0 });
354
- })),
355
- },
356
- {
357
- name: "delivers a keyed timer once when it is cancelled after the relay picked it up",
358
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
359
- const test = yield* ActorTest;
360
- const sender = yield* Outboxer.get("in-flight");
361
- const to = "in-flight-inbox";
362
- yield* sender.Schedule({ to, body: "firing", afterMs: 60_000, key: "k" });
363
- const pause = yield* test.pauseNext("beforeDelivery");
364
- const draining = yield* test.advance("1 minute").pipe(Effect.forkChild);
365
- yield* pause.reached;
366
- yield* sender.Cancel("k");
367
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 0 });
368
- yield* pause.release;
369
- yield* Fiber.join(draining);
370
- expect(yield* receivedBodies(to)).toEqual(["firing"]);
371
- yield* test.advance("1 hour");
372
- expect(yield* receivedBodies(to)).toEqual(["firing"]);
373
- })),
374
- },
375
- {
376
- name: "keeps an intent whose receiver defects and retries it with backoff",
377
- run: ({ expect, environment, fixture }) => environment.run(Effect.gen(function* () {
378
- const test = yield* ActorTest;
379
- const sender = yield* Outboxer.get("backoff");
380
- const inbox = yield* Inbox.get("backoff-inbox");
381
- yield* sender.Schedule({ to: "backoff-inbox", body: "retried", afterMs: 60_000 });
382
- fixture.failNext = true;
383
- yield* test.advance("1 minute");
384
- expect(yield* test.receiptsFor(inbox.ref, "Receive")).toBe(0);
385
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 1 });
386
- const sql = yield* SqlClient.SqlClient;
387
- expect(yield* sql `SELECT attempts FROM actor_outbox WHERE tenant_id = ${sender.ref.tenant}
388
- AND actor_type = 'Outboxer' AND actor_id = 'backoff'`).toEqual([{ attempts: 1 }]);
389
- yield* test.advance("1 second");
390
- expect(yield* receivedBodies("backoff-inbox")).toEqual(["retried"]);
391
- expect(yield* test.inspect(sender.ref)).toMatchObject({ outbox: 0 });
392
- })),
393
- },
394
- {
395
- name: "rejects escaped intent capabilities without writing an outbox row",
396
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
397
- const test = yield* ActorTest;
398
- const sender = yield* Outboxer.get("escape");
399
- yield* sender.Escape("escape-inbox");
400
- const stolen = yield* sender.Steal().pipe(Effect.exit);
401
- expect(Exit.isFailure(stolen) && Cause.pretty(stolen.cause)).toContain("Intent capability escaped its turn");
402
- const outside = yield* Intent.cancel("k").pipe(Effect.provideService(Actor.InTurn, Actor.InTurn.of({ turn: Symbol() })), Effect.exit);
403
- expect(Exit.isFailure(outside) && Cause.pretty(outside.cause)).toContain("Intent capability escaped its turn");
404
- yield* test.advance(0);
405
- expect(yield* test.inspect(sender.ref)).toMatchObject({ receipts: 1, outbox: 0 });
406
- expect(yield* receivedBodies("escape-inbox")).toEqual([]);
407
- })),
408
- },
409
- {
410
- name: "scans due work by bucket without reading sleeping actors' future timers",
411
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
412
- const sql = yield* SqlClient.SqlClient;
413
- const test = yield* ActorTest;
414
- yield* test.advance(0);
415
- const now = DateTime.toEpochMillis(yield* test.now);
416
- const tomorrow = now + 86_400_000;
417
- const { small, large } = yield* Effect.gen(function* () {
418
- yield* seedSleepers(1, 5_000, tomorrow);
419
- const small = yield* measureScan(now);
420
- yield* seedSleepers(5_001, 50_000, tomorrow);
421
- return yield* new Measured({ small, large: yield* measureScan(now) });
422
- }).pipe(sql.withTransaction, Effect.catchTag("Measured", Effect.succeed));
423
- for (const scan of [small, large]) {
424
- expect(scan).toMatchObject({ seqScans: 0, rows: 0, indexRows: 0 });
425
- expect(scan.indexes.filter((index) => index !== "actor_outbox_pkey" && index !== "actor_outbox_intent")).toEqual(["actor_outbox_due_kind"]);
426
- }
427
- expect(large.blocks <= 3 * 256).toBe(true);
428
- expect(yield* sql `SELECT count(*)::int AS sleepers FROM actor_generations
429
- WHERE tenant_id = 'scan'`).toEqual([{ sleepers: 0 }]);
430
- })),
431
- },
432
- ];
433
- /** The outbox actors. */
434
- export const outboxSuite = {
435
- fixture: outboxFixture,
436
- layer: outboxLayer,
437
- };
@@ -1,3 +0,0 @@
1
- import type { ConformanceCase } from "../conformance.ts";
2
- /** Payload-version cases: the migration's guard on populated databases, stored payload versions, and upcasting of older events and effects through the chain. */
3
- export declare const payloadMigrationsConformance: ReadonlyArray<ConformanceCase>;