@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,253 +0,0 @@
1
- import { Effect, Schema } from "effect";
2
- import { User } from "../../../index.js";
3
- import { InternalActors } from "../../../runtime/actors.js";
4
- import { Outcome, Request } from "../../../runtime/request.js";
5
- import { InternalCommandId } from "../../../identity/command.js";
6
- import { deliveryCommandId } from "../../../runtime/subscriptions/identity.js";
7
- import { ActorTest, executeForTest } from "../../actor-test.js";
8
- import { CLAIM_LEASE } from "../outbox.js";
9
- import { Refused, SubFollower, SubGated, SubGateOrder, SubOrder, } from "./actors.js";
10
- import { crashOnce, cursorRows, deliveryRequest, drain, followerLog, handlerRuns, logOf, outboxOf, query, run, sourceRows, subscriber, } from "./harness.js";
11
- /** Exactly-once delivery, receipts, and derived command ids of event subscriptions. */
12
- export const subscriptionDeliveryConformance = [
13
- {
14
- name: "acknowledges a redelivery whose receipt was pruned without running the handler",
15
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
16
- const test = yield* ActorTest;
17
- yield* (yield* SubFollower.get("pruned-follower")).Follow({ source: "pruned-order" });
18
- yield* drain;
19
- crashOnce(fixture, "beforeSettle", subscriber("pruned-follower"));
20
- yield* (yield* SubOrder.get("pruned-order")).Place({ customerId: "p", amount: 1 });
21
- yield* drain;
22
- expect(handlerRuns(fixture, "SubFollower/pruned-follower")).toBe(1);
23
- expect(yield* sourceRows("pruned-order")).toMatchObject([{ delivered: "0" }]);
24
- yield* query((sql) => sql `DELETE FROM actor_receipts WHERE tenant_id = ${test.tenant}
25
- AND actor_type = 'SubFollower' AND actor_id = 'pruned-follower' AND command = 'OnOrder'`);
26
- yield* test.advance(CLAIM_LEASE);
27
- expect(handlerRuns(fixture, "SubFollower/pruned-follower")).toBe(1);
28
- expect(yield* followerLog("pruned-follower")).toEqual(["pruned-order#1:OrderPlaced"]);
29
- expect(yield* sourceRows("pruned-order")).toMatchObject([
30
- { delivered: "1", due: false },
31
- ]);
32
- })),
33
- },
34
- {
35
- name: "applies each committed source event once when the relay dies before and after the subscriber's commit",
36
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
37
- const test = yield* ActorTest;
38
- const order = yield* SubOrder.get("crash-order");
39
- yield* (yield* SubFollower.get("crash-follower")).Follow({ source: "crash-order" });
40
- yield* drain;
41
- const commit = crashOnce(fixture, "beforeCommit", subscriber("crash-follower"));
42
- yield* order.Place({ customerId: "c", amount: 1 });
43
- yield* drain;
44
- expect(commit.crashed).toBe(true);
45
- const settle = crashOnce(fixture, "beforeSettle", subscriber("crash-follower"));
46
- yield* order.Place({ customerId: "c", amount: 2 });
47
- yield* drain;
48
- expect(settle.crashed).toBe(true);
49
- yield* test.advance(CLAIM_LEASE);
50
- yield* test.advance(CLAIM_LEASE);
51
- expect(yield* followerLog("crash-follower")).toEqual([
52
- "crash-order#1:OrderPlaced",
53
- "crash-order#2:OrderPlaced",
54
- ]);
55
- expect(yield* test.receiptsFor({ tenant: test.tenant, actor: "SubFollower", id: "crash-follower" }, "OnOrder")).toBe(2);
56
- })),
57
- },
58
- {
59
- name: "acknowledges a stale routed delivery as AlreadyApplied after a NotCreated skip and a later creation",
60
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
61
- const test = yield* ActorTest;
62
- const internal = yield* InternalActors;
63
- const order = yield* SubGateOrder.get("gate-order");
64
- yield* order.Place({ customerId: "gate-sub", amount: 1 });
65
- yield* drain;
66
- expect(handlerRuns(fixture, "SubGated/gate-sub")).toBe(0);
67
- expect(yield* cursorRows("SubGated", "gate-sub")).toMatchObject([
68
- { subscription: "GatedOrders", source_id: "gate-order", applied: "1" },
69
- ]);
70
- yield* (yield* SubGated.get("gate-sub")).OpenGated();
71
- yield* query((sql) => sql `DELETE FROM actor_receipts WHERE tenant_id = ${test.tenant}
72
- AND actor_type = 'SubGated' AND actor_id = 'gate-sub' AND command = 'OnGated'`);
73
- const stale = yield* deliveryRequest({
74
- subscriber: "gate-sub",
75
- source: "gate-order",
76
- epoch: "0",
77
- cursor: "1",
78
- route: {
79
- actor: "SubGated",
80
- subscription: "GatedOrders",
81
- command: "OnGated",
82
- source: "SubGateOrder",
83
- },
84
- });
85
- expect(yield* internal.deliver(stale)).toEqual(Outcome.cases.Acknowledged.make({ reason: "AlreadyApplied" }));
86
- expect(handlerRuns(fixture, "SubGated/gate-sub")).toBe(0);
87
- yield* order.Place({ customerId: "gate-sub", amount: 2 });
88
- yield* drain;
89
- expect(yield* logOf("SubGated", "gate-sub")).toEqual(["gate-order#2:OrderPlaced"]);
90
- })),
91
- },
92
- {
93
- name: "refuses a stale runner's delivery below the applied cursor after a lease takeover",
94
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
95
- const test = yield* ActorTest;
96
- const internal = yield* InternalActors;
97
- yield* (yield* SubFollower.get("stale-follower")).Follow({ source: "stale-order" });
98
- yield* drain;
99
- yield* (yield* SubOrder.get("stale-order")).PlaceMany({ customerId: "s", count: 2 });
100
- yield* drain;
101
- yield* query((sql) => sql `DELETE FROM actor_receipts WHERE tenant_id = ${test.tenant}
102
- AND actor_type = 'SubFollower' AND actor_id = 'stale-follower'`);
103
- const stale = yield* deliveryRequest({
104
- subscriber: "stale-follower",
105
- source: "stale-order",
106
- epoch: "1",
107
- cursor: "1",
108
- });
109
- expect(yield* internal.deliver(stale)).toEqual(Outcome.cases.Acknowledged.make({ reason: "AlreadyApplied" }));
110
- const older = yield* deliveryRequest({
111
- subscriber: "stale-follower",
112
- source: "stale-order",
113
- epoch: "0",
114
- cursor: "2",
115
- });
116
- expect(yield* internal.deliver(older)).toEqual(Outcome.cases.Acknowledged.make({ reason: "Stale" }));
117
- expect(handlerRuns(fixture, "SubFollower/stale-follower")).toBe(2);
118
- })),
119
- },
120
- {
121
- name: "advances past a declared failure and replays its receipt",
122
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
123
- const internal = yield* InternalActors;
124
- yield* (yield* SubFollower.get("declared-follower")).Follow({
125
- source: "declared-order",
126
- });
127
- yield* drain;
128
- fixture.behave = (entry) => (entry.endsWith("#1:OrderPlaced") ? "refuse" : "apply");
129
- yield* (yield* SubOrder.get("declared-order")).PlaceMany({ customerId: "d", count: 2 });
130
- yield* drain;
131
- expect(yield* followerLog("declared-follower")).toEqual([
132
- "declared-order#2:OrderPlaced",
133
- ]);
134
- expect(yield* cursorRows("SubFollower", "declared-follower")).toMatchObject([
135
- { applied: "2" },
136
- ]);
137
- const replay = yield* internal.deliver(yield* deliveryRequest({
138
- subscriber: "declared-follower",
139
- source: "declared-order",
140
- epoch: "1",
141
- cursor: "1",
142
- }));
143
- expect(Outcome.guards.Failure(replay)).toBe(true);
144
- expect(handlerRuns(fixture, "SubFollower/declared-follower")).toBe(2);
145
- })),
146
- },
147
- {
148
- name: "replays after a schema-compatible deploy instead of CommandConflict",
149
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
150
- const internal = yield* InternalActors;
151
- yield* (yield* SubFollower.get("deploy-follower")).Follow({ source: "deploy-order" });
152
- yield* drain;
153
- yield* (yield* SubOrder.get("deploy-order")).Place({ customerId: "d", amount: 1 });
154
- yield* drain;
155
- const redelivered = yield* deliveryRequest({
156
- subscriber: "deploy-follower",
157
- source: "deploy-order",
158
- epoch: "1",
159
- cursor: "1",
160
- extra: true,
161
- });
162
- expect(Outcome.guards.Success(yield* internal.deliver(redelivered))).toBe(true);
163
- expect(handlerRuns(fixture, "SubFollower/deploy-follower")).toBe(1);
164
- })),
165
- },
166
- {
167
- name: "derives distinct command ids for two subscriptions, two subscribers, and two epochs of one source",
168
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
169
- const subscriber = { tenant: "t", actor: "SubFollower", id: "a" };
170
- const envelope = {
171
- subscription: "FollowedOrders",
172
- sourceType: "SubOrder",
173
- sourceId: "o",
174
- epoch: "1",
175
- kind: "event",
176
- position: "1",
177
- };
178
- const ids = yield* Effect.forEach([
179
- [subscriber, envelope],
180
- [subscriber, { ...envelope, subscription: "Other" }],
181
- [{ ...subscriber, id: "b" }, envelope],
182
- [subscriber, { ...envelope, epoch: "2" }],
183
- [subscriber, { ...envelope, kind: "gap" }],
184
- ], ([ref, env]) => deliveryCommandId({
185
- subscriber: ref,
186
- envelope: env,
187
- issuedAt: 1_000,
188
- retryWindowMs: 60_000,
189
- }));
190
- expect(new Set(ids).size).toBe(ids.length);
191
- expect(yield* deliveryCommandId({
192
- subscriber,
193
- envelope,
194
- issuedAt: 1_000,
195
- retryWindowMs: 60_000,
196
- })).toBe(ids[0]);
197
- for (const id of ids) {
198
- expect(Schema.is(InternalCommandId)(id)).toBe(true);
199
- expect(id.startsWith("v1.1000.61000.")).toBe(true);
200
- expect(id.split(".")[3][14]).toBe("8");
201
- }
202
- })),
203
- },
204
- {
205
- name: "accepts a version-8 derived id on System delivery and rejects it at external admission",
206
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
207
- yield* (yield* SubFollower.get("external-follower")).Follow({
208
- source: "external-order",
209
- });
210
- yield* drain;
211
- yield* (yield* SubOrder.get("external-order")).Place({ customerId: "e", amount: 1 });
212
- yield* drain;
213
- expect(handlerRuns(fixture, "SubFollower/external-follower")).toBe(1);
214
- const delivery = yield* deliveryRequest({
215
- subscriber: "external-follower",
216
- source: "external-order",
217
- epoch: "1",
218
- cursor: "1",
219
- });
220
- const withEnvelope = yield* executeForTest(delivery).pipe(Effect.flip);
221
- expect(withEnvelope.reason._tag).toBe("Unauthorized");
222
- const { delivery: _, ...bare } = delivery;
223
- const withCaller = yield* executeForTest(Request.make(bare)).pipe(Effect.flip);
224
- expect(withCaller.reason._tag).toBe("Unauthorized");
225
- const asUser = yield* executeForTest(Request.make({
226
- ...bare,
227
- ref: { ...bare.ref, actor: "SubFollower" },
228
- caller: User.make({ subject: "alice" }),
229
- command: "Touch",
230
- payload: "{}",
231
- })).pipe(Effect.flip);
232
- expect(asUser.reason._tag).toBe("InvalidCommandId");
233
- expect(handlerRuns(fixture, "SubFollower/external-follower")).toBe(1);
234
- })),
235
- },
236
- {
237
- name: "delivers nothing for a rolled-back source turn",
238
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
239
- yield* (yield* SubFollower.get("rollback-follower")).Follow({
240
- source: "rollback-order",
241
- });
242
- yield* drain;
243
- const order = yield* SubOrder.get("rollback-order");
244
- expect(yield* order.PlaceThenRefuse("rb").pipe(Effect.flip)).toBeInstanceOf(Refused);
245
- yield* order.PlaceThenDie("rb").pipe(Effect.exit);
246
- yield* drain;
247
- expect(yield* outboxOf("SubOrder", "rollback-order", "feed")).toBe(0);
248
- expect(yield* followerLog("rollback-follower")).toEqual([]);
249
- expect(yield* logOf("SubSummary", "rb")).toEqual([]);
250
- expect(handlerRuns(fixture, "SubFollower/rollback-follower")).toBe(0);
251
- })),
252
- },
253
- ];
@@ -1,4 +0,0 @@
1
- import type { ConformanceCase } from "../../conformance.ts";
2
- import { type SubscriptionsFixture } from "./actors.ts";
3
- /** Deploy-time registration checks and tag-summary upkeep of event subscriptions. */
4
- export declare const subscriptionDeployConformance: ReadonlyArray<ConformanceCase<SubscriptionsFixture>>;
@@ -1,162 +0,0 @@
1
- import { Cause, Effect, Exit, Layer } from "effect";
2
- import { SqlClient } from "effect/sql";
3
- import { Tenant } from "../../../index.js";
4
- import { ActorTest } from "../../actor-test.js";
5
- import { SubFollower, SubOrder, subOrderLayer } from "./actors.js";
6
- import { drain, followerLog, handlerRuns, query, run, sourceRows, tagMismatches, } from "./harness.js";
7
- import { CLAIM_LEASE } from "../outbox.js";
8
- /** Deploy-time registration checks and tag-summary upkeep of event subscriptions. */
9
- export const subscriptionDeployConformance = [
10
- {
11
- name: "delivers a class added to a dynamic subscription by a deploy, and never narrows a row",
12
- run: ({ expect, environment, fixture }) => Effect.gen(function* () {
13
- const tenant = yield* Effect.promise(() => run(environment, fixture, Effect.gen(function* () {
14
- const test = yield* ActorTest;
15
- yield* (yield* SubFollower.get("widen-follower")).Follow({ source: "widen-order" });
16
- yield* drain;
17
- yield* query((sql) => sql `UPDATE actor_subscriptions SET events = ARRAY['OrderPlaced']
18
- WHERE tenant_id = ${test.tenant} AND source_id = 'widen-order'
19
- AND subscriber_id = 'widen-follower'`);
20
- yield* query((sql) => sql `DELETE FROM actor_subscription_tags WHERE tenant_id = ${test.tenant}
21
- AND source_id = 'widen-order' AND event = 'OrderCancelled'`);
22
- expect(yield* tagMismatches).toEqual([]);
23
- return test.tenant;
24
- })));
25
- yield* environment.restart;
26
- yield* Effect.promise(() => run(environment, fixture, Effect.gen(function* () {
27
- const events = query((sql) => sql `SELECT to_jsonb(events)::text AS events
28
- FROM actor_subscriptions WHERE tenant_id = ${tenant}
29
- AND source_id = 'widen-order' AND subscriber_id = 'widen-follower'`);
30
- expect((yield* events)[0].events).toBe('["OrderCancelled", "OrderPlaced"]');
31
- expect(yield* tagMismatches).toEqual([]);
32
- yield* Effect.gen(function* () {
33
- yield* (yield* SubOrder.get("widen-order")).CancelOrder("w");
34
- }).pipe(Effect.provideService(Tenant, tenant));
35
- yield* drain;
36
- const { state } = yield* (yield* ActorTest).inspect({
37
- tenant,
38
- actor: "SubFollower",
39
- id: "widen-follower",
40
- });
41
- expect(state).toEqual({ log: ["widen-order#1:OrderCancelled"] });
42
- })));
43
- }).pipe(Effect.runPromise),
44
- },
45
- {
46
- name: "never claims a row widened with a class this runner does not declare, and leaves it due",
47
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
48
- const test = yield* ActorTest;
49
- yield* (yield* SubFollower.get("older-follower")).Follow({ source: "older-order" });
50
- yield* drain;
51
- yield* query((sql) => sql `UPDATE actor_subscriptions
52
- SET events = ARRAY['OrderCancelled', 'OrderNoted', 'OrderPlaced']
53
- WHERE tenant_id = ${test.tenant} AND source_id = 'older-order'
54
- AND subscriber_id = 'older-follower'`);
55
- yield* (yield* SubOrder.get("older-order")).Place({ customerId: "o", amount: 1 });
56
- yield* drain;
57
- yield* test.advance(CLAIM_LEASE);
58
- expect(handlerRuns(fixture, "SubFollower/older-follower")).toBe(0);
59
- expect(yield* followerLog("older-follower")).toEqual([]);
60
- expect(yield* sourceRows("older-order")).toMatchObject([
61
- {
62
- subscriber_id: "older-follower",
63
- active: true,
64
- delivered: "0",
65
- due: true,
66
- attempts: 0,
67
- },
68
- ]);
69
- yield* query((sql) => sql `UPDATE actor_subscriptions SET events = ARRAY['OrderCancelled', 'OrderPlaced']
70
- WHERE tenant_id = ${test.tenant} AND source_id = 'older-order'
71
- AND subscriber_id = 'older-follower'`);
72
- yield* test.advance(CLAIM_LEASE);
73
- expect(yield* followerLog("older-follower")).toEqual(["older-order#1:OrderPlaced"]);
74
- expect(yield* tagMismatches).toEqual([]);
75
- })),
76
- },
77
- {
78
- name: "fails registration of a source served without a subscriber type that routes from it",
79
- requiresFreshDatabase: true,
80
- requiresIndependentConnections: true,
81
- run: ({ expect, environment }) => environment.run(Effect.gen(function* () {
82
- const database = yield* environment.freshDatabase;
83
- const runtime = (record) => Layer.build(Layer.fresh(subOrderLayer).pipe(Layer.provideMerge(ActorTest.layer({ database })))).pipe(Effect.flatMap((context) => record.pipe(Effect.provideContext(context))), Effect.scoped, Effect.exit);
84
- const alone = yield* runtime(query((sql) => sql `INSERT INTO actor_routed_subscriptions (source_type, subscriber_type, subscription)
85
- VALUES ('SubOrder', 'SubSummary', 'CustomerOrders')`));
86
- expect(Exit.isSuccess(alone)).toBe(true);
87
- const partial = yield* runtime(Effect.void);
88
- expect(Exit.isFailure(partial) &&
89
- Cause.pretty(partial.cause).includes("Actor SubOrder is registered without the subscriber types that route from it")).toBe(true);
90
- })),
91
- timeoutMs: 60_000,
92
- },
93
- {
94
- name: "keeps the tag summary equal to the rows after every insert, widen, and delete",
95
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
96
- const test = yield* ActorTest;
97
- const followers = ["tags-a", "tags-b", "tags-c"];
98
- for (const id of followers)
99
- yield* (yield* SubFollower.get(id)).Follow({ source: "tags-order" });
100
- yield* drain;
101
- expect(yield* tagMismatches).toEqual([]);
102
- const counts = () => query((sql) => sql `SELECT event, rows FROM actor_subscription_tags
103
- WHERE tenant_id = ${test.tenant} AND source_id = 'tags-order' ORDER BY event`);
104
- expect(yield* counts()).toEqual([
105
- { event: "OrderCancelled", rows: 3 },
106
- { event: "OrderPlaced", rows: 3 },
107
- ]);
108
- yield* (yield* SubFollower.get("tags-b")).Unfollow("tags-order");
109
- yield* drain;
110
- expect(yield* counts()).toEqual([
111
- { event: "OrderCancelled", rows: 2 },
112
- { event: "OrderPlaced", rows: 2 },
113
- ]);
114
- yield* (yield* SubOrder.get("tags-order")).Place({ customerId: "tags-x", amount: 1 });
115
- yield* drain;
116
- expect(yield* counts()).toEqual([
117
- { event: "OrderCancelled", rows: 4 },
118
- { event: "OrderPlaced", rows: 5 },
119
- ]);
120
- yield* (yield* SubFollower.get("tags-a")).Unfollow("tags-order");
121
- yield* (yield* SubFollower.get("tags-c")).Unfollow("tags-order");
122
- yield* drain;
123
- expect(yield* counts()).toEqual([
124
- { event: "OrderCancelled", rows: 2 },
125
- { event: "OrderPlaced", rows: 3 },
126
- ]);
127
- expect(yield* tagMismatches).toEqual([]);
128
- })),
129
- },
130
- {
131
- name: "keeps the tag summary exact when many subscriptions of one source change at once, and deletes counts that reach zero",
132
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
133
- const test = yield* ActorTest;
134
- const ids = Array.from({ length: 16 }, (_, index) => `crowd-${index}`);
135
- const counts = query((sql) => sql `SELECT event, rows
136
- FROM actor_subscription_tags
137
- WHERE tenant_id = ${test.tenant} AND source_id = 'crowd-order' ORDER BY event`);
138
- yield* Effect.forEach(ids, (id) => SubFollower.get(id).pipe(Effect.flatMap((follower) => follower.Follow({ source: "crowd-order" }))), { concurrency: "unbounded", discard: true });
139
- yield* drain;
140
- expect(yield* counts).toEqual([
141
- { event: "OrderCancelled", rows: 16 },
142
- { event: "OrderPlaced", rows: 16 },
143
- ]);
144
- yield* Effect.forEach(ids, (id, index) => SubFollower.get(id).pipe(Effect.flatMap((follower) => index % 2 === 0
145
- ? follower.Unfollow("crowd-order")
146
- : follower
147
- .Unfollow("crowd-order")
148
- .pipe(Effect.andThen(follower.Follow({ source: "crowd-order" }))))), { concurrency: "unbounded", discard: true });
149
- yield* drain;
150
- expect(yield* counts).toEqual([
151
- { event: "OrderCancelled", rows: 8 },
152
- { event: "OrderPlaced", rows: 8 },
153
- ]);
154
- expect(yield* tagMismatches).toEqual([]);
155
- yield* Effect.forEach(ids, (id) => SubFollower.get(id).pipe(Effect.flatMap((follower) => follower.Unfollow("crowd-order"))), { concurrency: "unbounded", discard: true });
156
- yield* drain;
157
- expect(yield* counts).toEqual([]);
158
- expect(yield* tagMismatches).toEqual([]);
159
- })),
160
- timeoutMs: 60_000,
161
- },
162
- ];
@@ -1,4 +0,0 @@
1
- import type { ConformanceCase } from "../../conformance.ts";
2
- import { type SubscriptionsFixture } from "./actors.ts";
3
- /** Unsubscribe, resubscribe, and control-row epochs of event subscriptions. */
4
- export declare const subscriptionEpochConformance: ReadonlyArray<ConformanceCase<SubscriptionsFixture>>;
@@ -1,169 +0,0 @@
1
- import { Effect, Fiber } from "effect";
2
- import { ActorTest } from "../../actor-test.js";
3
- import { CLAIM_LEASE } from "../outbox.js";
4
- import { SubFollower, SubOrder } from "./actors.js";
5
- import { cursorRows, drain, followerLog, handlerRuns, outboxOf, pauseOnce, run, sourceRows, subscriber, tagMismatches, } from "./harness.js";
6
- /** Unsubscribe, resubscribe, and control-row epochs of event subscriptions. */
7
- export const subscriptionEpochConformance = [
8
- {
9
- name: "runs no handler for a delivery in flight when unsubscribe commits",
10
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
11
- const follower = yield* SubFollower.get("inflight-follower");
12
- yield* follower.Follow({ source: "inflight-order" });
13
- yield* drain;
14
- const pause = yield* pauseOnce(fixture, "beforeDelivery", subscriber("inflight-follower"));
15
- yield* (yield* SubOrder.get("inflight-order")).Place({ customerId: "i", amount: 1 });
16
- const draining = yield* drain.pipe(Effect.forkChild);
17
- yield* pause.reached;
18
- yield* follower.Unfollow("inflight-order");
19
- yield* pause.release;
20
- yield* Fiber.join(draining);
21
- yield* drain;
22
- expect(handlerRuns(fixture, "SubFollower/inflight-follower")).toBe(0);
23
- expect(yield* followerLog("inflight-follower")).toEqual([]);
24
- expect(yield* sourceRows("inflight-order")).toMatchObject([
25
- { subscriber_id: "inflight-follower", epoch: "2", active: false, due: false },
26
- ]);
27
- expect(yield* tagMismatches).toEqual([]);
28
- })),
29
- },
30
- {
31
- name: "keeps the newest epoch when subscribe and unsubscribe control rows are delivered out of order",
32
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
33
- const test = yield* ActorTest;
34
- const follower = yield* SubFollower.get("order-follower");
35
- const pause = yield* test.pauseNext("afterClaim");
36
- yield* follower.Follow({ source: "order-order" });
37
- const draining = yield* drain.pipe(Effect.forkChild);
38
- yield* pause.reached;
39
- yield* follower.Unfollow("order-order");
40
- for (;;) {
41
- const rows = yield* sourceRows("order-order");
42
- if (rows.some((row) => row.epoch === "2"))
43
- break;
44
- yield* Effect.sleep("20 millis");
45
- }
46
- yield* pause.release;
47
- yield* Fiber.join(draining);
48
- yield* (yield* SubOrder.get("order-order")).Place({ customerId: "o", amount: 1 });
49
- yield* drain;
50
- expect(yield* sourceRows("order-order")).toMatchObject([
51
- { subscriber_id: "order-follower", epoch: "2", active: false, due: false },
52
- ]);
53
- expect(yield* followerLog("order-follower")).toEqual([]);
54
- expect(yield* tagMismatches).toEqual([]);
55
- })),
56
- },
57
- {
58
- name: 'runs no stale-epoch delivery after unsubscribe and resubscribe with from: "start", and applies the new epoch from cursor 1',
59
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
60
- const follower = yield* SubFollower.get("resub-follower");
61
- yield* follower.Follow({ source: "resub-order" });
62
- yield* drain;
63
- const pause = yield* pauseOnce(fixture, "beforeDelivery", subscriber("resub-follower"));
64
- yield* (yield* SubOrder.get("resub-order")).Place({ customerId: "r", amount: 1 });
65
- const draining = yield* drain.pipe(Effect.forkChild);
66
- yield* pause.reached;
67
- yield* follower.Unfollow("resub-order");
68
- yield* follower.Follow({ source: "resub-order", from: "start" });
69
- for (;;) {
70
- const rows = yield* sourceRows("resub-order");
71
- if (rows.some((row) => row.epoch === "3"))
72
- break;
73
- yield* Effect.sleep("20 millis");
74
- }
75
- yield* pause.release;
76
- yield* Fiber.join(draining);
77
- yield* drain;
78
- expect(yield* followerLog("resub-follower")).toEqual(["resub-order#1:OrderPlaced"]);
79
- expect(handlerRuns(fixture, "SubFollower/resub-follower")).toBe(1);
80
- expect(yield* cursorRows("SubFollower", "resub-follower")).toMatchObject([
81
- { epoch: "3", active: true, applied: "1" },
82
- ]);
83
- expect(yield* sourceRows("resub-order")).toMatchObject([
84
- { subscriber_id: "resub-follower", epoch: "3", active: true, delivered: "1" },
85
- ]);
86
- expect(yield* tagMismatches).toEqual([]);
87
- })),
88
- },
89
- {
90
- name: 'fences a delivery settling after unsubscribe and resubscribe with from: "start", keeping the tag summary exact',
91
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
92
- const follower = yield* SubFollower.get("late-follower");
93
- yield* follower.Follow({ source: "late-order" });
94
- yield* drain;
95
- const pause = yield* pauseOnce(fixture, "beforeSettle", subscriber("late-follower"));
96
- yield* (yield* SubOrder.get("late-order")).Place({ customerId: "l", amount: 1 });
97
- const draining = yield* drain.pipe(Effect.forkChild);
98
- yield* pause.reached;
99
- expect(handlerRuns(fixture, "SubFollower/late-follower")).toBe(1);
100
- yield* follower.Unfollow("late-order");
101
- yield* follower.Follow({ source: "late-order", from: "start" });
102
- for (;;) {
103
- const rows = yield* sourceRows("late-order");
104
- if (rows.some((row) => row.epoch === "3"))
105
- break;
106
- yield* Effect.sleep("20 millis");
107
- }
108
- yield* pause.release;
109
- yield* Fiber.join(draining);
110
- yield* drain;
111
- expect(handlerRuns(fixture, "SubFollower/late-follower")).toBe(2);
112
- expect(yield* followerLog("late-follower")).toEqual([
113
- "late-order#1:OrderPlaced",
114
- "late-order#1:OrderPlaced",
115
- ]);
116
- expect(yield* cursorRows("SubFollower", "late-follower")).toMatchObject([
117
- { epoch: "3", active: true, applied: "1" },
118
- ]);
119
- expect(yield* sourceRows("late-order")).toMatchObject([
120
- {
121
- subscriber_id: "late-follower",
122
- epoch: "3",
123
- active: true,
124
- delivered: "1",
125
- due: false,
126
- },
127
- ]);
128
- expect(yield* tagMismatches).toEqual([]);
129
- })),
130
- },
131
- {
132
- name: "makes no change when a control row reruns at the same epoch after a crash",
133
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
134
- const test = yield* ActorTest;
135
- const order = yield* SubOrder.get("rerun-order");
136
- yield* order.Place({ customerId: "x", amount: 1 });
137
- yield* test.crashNext("beforeOutboxDelete");
138
- yield* (yield* SubFollower.get("rerun-follower")).Follow({ source: "rerun-order" });
139
- yield* drain;
140
- expect(yield* outboxOf("SubFollower", "rerun-follower", "control")).toBe(1);
141
- const registered = yield* sourceRows("rerun-order");
142
- yield* order.Place({ customerId: "x", amount: 2 });
143
- yield* drain;
144
- yield* test.advance(CLAIM_LEASE);
145
- expect(yield* outboxOf("SubFollower", "rerun-follower", "control")).toBe(0);
146
- expect(yield* followerLog("rerun-follower")).toEqual(["rerun-order#2:OrderPlaced"]);
147
- expect(registered).toMatchObject([{ epoch: "1", delivered: "1" }]);
148
- expect(yield* sourceRows("rerun-order")).toMatchObject([
149
- { epoch: "1", active: true, delivered: "2" },
150
- ]);
151
- expect(yield* tagMismatches).toEqual([]);
152
- })),
153
- },
154
- {
155
- name: "registers a subscription once when the relay dies after the control claim, before the registration statement",
156
- run: ({ expect, environment, fixture }) => run(environment, fixture, Effect.gen(function* () {
157
- const test = yield* ActorTest;
158
- yield* test.crashNext("afterClaim");
159
- yield* (yield* SubFollower.get("claimdie-follower")).Follow({ source: "claimdie-order" });
160
- yield* drain;
161
- expect(yield* sourceRows("claimdie-order")).toEqual([]);
162
- yield* test.advance(CLAIM_LEASE);
163
- yield* (yield* SubOrder.get("claimdie-order")).Place({ customerId: "c", amount: 1 });
164
- yield* drain;
165
- expect(yield* followerLog("claimdie-follower")).toEqual(["claimdie-order#1:OrderPlaced"]);
166
- expect(yield* tagMismatches).toEqual([]);
167
- })),
168
- },
169
- ];
@@ -1,4 +0,0 @@
1
- import type { ConformanceCase } from "../../conformance.ts";
2
- import { type SubscriptionsFixture } from "./actors.ts";
3
- /** Blocking, ordering, and backoff of failing subscription deliveries. */
4
- export declare const subscriptionFailureConformance: ReadonlyArray<ConformanceCase<SubscriptionsFixture>>;