| ... | ... | @@ -272,3 +272,61 @@ it.effect("uses indexed high-water lookups for populated history without OR scan |
| 272 | 272 | ), |
| 273 | 273 | ), |
| 274 | 274 | ); |
| 275 | |
| 276 | it.effect("replays a command's events through the command index, not the sequence range", () => |
| 277 | Effect.gen(function* () { |
| 278 | const store = yield* OrchestrationEventStore.OrchestrationEventStore; |
| 279 | const sql = yield* SqlClient.SqlClient; |
| 280 | yield* runMigrations(); |
| 281 | yield* sql` |
| 282 | WITH RECURSIVE history(n) AS ( |
| 283 | SELECT 1 UNION ALL SELECT n + 1 FROM history WHERE n < 25000 |
| 284 | ) |
| 285 | INSERT INTO orchestration_events ( |
| 286 | event_id, aggregate_kind, stream_id, stream_version, event_type, occurred_at, |
| 287 | command_id, actor_kind, payload_json, metadata_json, application_event_version |
| 288 | ) |
| 289 | SELECT 'history:' || n, 'thread', 'thread', n, 'provider-session.detached', ${occurredAt}, |
| 290 | CASE WHEN n IN (12, 24990) THEN 'retried-command' ELSE 'command:' || n END, |
| 291 | 'server', |
| 292 | '{"providerSessionId":"session","detachedAt":"' || ${occurredAt} || '"}', |
| 293 | '{}', 2 |
| 294 | FROM history |
| 295 | `; |
| 296 | const statements: Array<string> = []; |
| 297 | const tracer = Tracer.make({ |
| 298 | span(options) { |
| 299 | const span = new Tracer.NativeSpan(options); |
| 300 | const end = span.end.bind(span); |
| 301 | span.end = (endTime, exit) => { |
| 302 | end(endTime, exit); |
| 303 | const query = span.attributes.get("db.query.text"); |
| 304 | if (typeof query === "string") statements.push(query); |
| 305 | }; |
| 306 | return span; |
| 307 | }, |
| 308 | }); |
| 309 | const replayed = yield* store |
| 310 | .readAgentEvents({ commandId: CommandId.make("retried-command") }) |
| 311 | .pipe(Stream.runCollect, Effect.withTracer(tracer)); |
| 312 | assert.deepEqual( |
| 313 | replayed.map((event) => event.sequence), |
| 314 | [12, 24990], |
| 315 | ); |
| 316 | assert.equal(statements.length, 1); |
| 317 | const plan = yield* sql.unsafe<{ readonly detail: string }>( |
| 318 | `EXPLAIN QUERY PLAN ${statements[0]}`, |
| 319 | [0, Number.MAX_SAFE_INTEGER, "retried-command", 500], |
| 320 | ); |
| 321 | assert.match( |
| 322 | plan.map((row) => row.detail).join("\n"), |
| 323 | /SEARCH orchestration_events USING INDEX idx_orch_events_command_id \(command_id=\?/, |
| 324 | ); |
| 325 | }).pipe( |
| 326 | Effect.provide( |
| 327 | OrchestrationEventStore.layer.pipe( |
| 328 | Layer.provideMerge(NodeSqliteClient.layer({ filename: ":memory:" })), |
| 329 | ), |
| 330 | ), |
| 331 | ), |
| 332 | ); |