@ddd-ts/event-sourcing-firestore 0.0.0-compute-timeout-on-process.9 → 0.0.0-compute-timeout-on-process.11

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.
@@ -0,0 +1,16 @@
1
+ import type { IEsEvent, ISavedChange } from "@ddd-ts/core";
2
+ export declare class EventCoordinator {
3
+ private eventProcessing;
4
+ private currentEventId;
5
+ private lastEvent;
6
+ private isRunning;
7
+ private _onEmpty;
8
+ addEvent(event: ISavedChange<IEsEvent>): void;
9
+ start(event: ISavedChange<IEsEvent>): () => void;
10
+ waitCurrentEvent(): Promise<void>;
11
+ cleanEvent(event: ISavedChange<IEsEvent>): void;
12
+ canProceed(event: ISavedChange<IEsEvent>): boolean;
13
+ onEmpty(callback: () => void): void;
14
+ checkEmpty(): void;
15
+ }
16
+ //# sourceMappingURL=event-coordinator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-coordinator.d.ts","sourceRoot":"","sources":["../../src/projection/event-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG3D,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,eAAe,CAAkD;IACzE,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAY;IAE5B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC;IAYtC,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC;IAU7B,gBAAgB;IAMtB,UAAU,CAAC,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC;IAYxC,UAAU,CAAC,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC;IAMxC,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI;IAI5B,UAAU;CAKX"}
@@ -0,0 +1,47 @@
1
+ const require_promise_with_resolvers = require('../utils/promise-with-resolvers.js');
2
+
3
+ //#region src/projection/event-coordinator.ts
4
+ var EventCoordinator = class {
5
+ eventProcessing = /* @__PURE__ */ new Map();
6
+ currentEventId = null;
7
+ lastEvent = null;
8
+ isRunning = false;
9
+ _onEmpty = () => {};
10
+ addEvent(event) {
11
+ const eventId = event.id.serialize();
12
+ this.eventProcessing.set(eventId, require_promise_with_resolvers.promiseWithResolvers());
13
+ if (this.lastEvent === null || this.lastEvent.revision < event.revision) this.lastEvent = event;
14
+ }
15
+ start(event) {
16
+ if (this.isRunning) throw new Error("Event processing already in progress");
17
+ this.currentEventId = event.id.serialize();
18
+ this.isRunning = true;
19
+ return () => this.cleanEvent(event);
20
+ }
21
+ async waitCurrentEvent() {
22
+ if (!this.currentEventId) return;
23
+ await this.eventProcessing.get(this.currentEventId)?.promise;
24
+ }
25
+ cleanEvent(event) {
26
+ const eventId = event.id.serialize();
27
+ this.eventProcessing.get(eventId)?.resolve();
28
+ this.eventProcessing.delete(eventId);
29
+ this.isRunning = false;
30
+ this.currentEventId = null;
31
+ this.checkEmpty();
32
+ }
33
+ canProceed(event) {
34
+ if (this.isRunning) return false;
35
+ const eventId = event.id.serialize();
36
+ return this.lastEvent?.id.serialize() === eventId;
37
+ }
38
+ onEmpty(callback) {
39
+ this._onEmpty = callback;
40
+ }
41
+ checkEmpty() {
42
+ if (this.eventProcessing.size === 0) this._onEmpty();
43
+ }
44
+ };
45
+
46
+ //#endregion
47
+ exports.EventCoordinator = EventCoordinator;
@@ -0,0 +1,47 @@
1
+ import { promiseWithResolvers } from "../utils/promise-with-resolvers.mjs";
2
+
3
+ //#region src/projection/event-coordinator.ts
4
+ var EventCoordinator = class {
5
+ eventProcessing = /* @__PURE__ */ new Map();
6
+ currentEventId = null;
7
+ lastEvent = null;
8
+ isRunning = false;
9
+ _onEmpty = () => {};
10
+ addEvent(event) {
11
+ const eventId = event.id.serialize();
12
+ this.eventProcessing.set(eventId, promiseWithResolvers());
13
+ if (this.lastEvent === null || this.lastEvent.revision < event.revision) this.lastEvent = event;
14
+ }
15
+ start(event) {
16
+ if (this.isRunning) throw new Error("Event processing already in progress");
17
+ this.currentEventId = event.id.serialize();
18
+ this.isRunning = true;
19
+ return () => this.cleanEvent(event);
20
+ }
21
+ async waitCurrentEvent() {
22
+ if (!this.currentEventId) return;
23
+ await this.eventProcessing.get(this.currentEventId)?.promise;
24
+ }
25
+ cleanEvent(event) {
26
+ const eventId = event.id.serialize();
27
+ this.eventProcessing.get(eventId)?.resolve();
28
+ this.eventProcessing.delete(eventId);
29
+ this.isRunning = false;
30
+ this.currentEventId = null;
31
+ this.checkEmpty();
32
+ }
33
+ canProceed(event) {
34
+ if (this.isRunning) return false;
35
+ const eventId = event.id.serialize();
36
+ return this.lastEvent?.id.serialize() === eventId;
37
+ }
38
+ onEmpty(callback) {
39
+ this._onEmpty = callback;
40
+ }
41
+ checkEmpty() {
42
+ if (this.eventProcessing.size === 0) this._onEmpty();
43
+ }
44
+ };
45
+
46
+ //#endregion
47
+ export { EventCoordinator };
@@ -14,9 +14,6 @@ interface FirestoreProjectorConfig {
14
14
  };
15
15
  onProcessError: (error: Error) => void;
16
16
  onEnqueueError: (error: Error) => void;
17
- debounce?: {
18
- delayMs: number;
19
- };
20
17
  }
21
18
  export declare class FirestoreProjector {
22
19
  readonly projection: ESProjection<IEsEvent>;
@@ -26,8 +23,8 @@ export declare class FirestoreProjector {
26
23
  _unclaim: boolean;
27
24
  constructor(projection: ESProjection<IEsEvent>, reader: ProjectedStreamReader<IEsEvent>, queue: FirestoreQueueStore, config?: FirestoreProjectorConfig);
28
25
  breathe(): AsyncGenerator<readonly [number, () => void], void, unknown>;
29
- private checkpointTsTriggered;
30
- private shouldProceedAfterDebounce;
26
+ private eventCoordinators;
27
+ private getEventCoordinator;
31
28
  handle(savedChange: ISavedChange<IEsEvent>): Promise<void>;
32
29
  private getCursor;
33
30
  private attempt;
@@ -1 +1 @@
1
- {"version":3,"file":"firestore.projector.d.ts","sourceRoot":"","sources":["../../src/projection/firestore.projector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"firestore.projector.d.ts","sourceRoot":"","sources":["../../src/projection/firestore.projector.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  const require_runtime = require('../_virtual/_rolldown/runtime.js');
2
+ const require_event_coordinator = require('./event-coordinator.js');
2
3
  let _ddd_ts_core = require("@ddd-ts/core");
3
4
  let _ddd_ts_store_firestore = require("@ddd-ts/store-firestore");
4
5
  let firebase_admin_firestore = require("firebase-admin/firestore");
@@ -26,7 +27,6 @@ var FirestoreProjector = class {
26
27
  maxDelay: 200,
27
28
  backoff: 1.5
28
29
  },
29
- debounce: { delayMs: 0 },
30
30
  enqueue: { batchSize: 100 },
31
31
  onProcessError: (error) => {
32
32
  console.error("Error processing event:", error);
@@ -52,21 +52,32 @@ var FirestoreProjector = class {
52
52
  await wait((backoff * i + 1) * minDelay + jitter);
53
53
  }
54
54
  }
55
- checkpointTsTriggered = /* @__PURE__ */ new Map();
56
- async shouldProceedAfterDebounce(event) {
57
- const debounceDelay = this.config.debounce?.delayMs;
58
- if (!debounceDelay) return true;
59
- const checkpointId = this.projection.getCheckpointId(event).serialize();
60
- const currentTs = process.hrtime.bigint();
61
- this.checkpointTsTriggered.set(checkpointId, currentTs);
62
- await wait(debounceDelay);
63
- return this.checkpointTsTriggered.get(checkpointId) === currentTs;
55
+ eventCoordinators = /* @__PURE__ */ new Map();
56
+ getEventCoordinator(checkpointId) {
57
+ const key = checkpointId.serialize();
58
+ let coordinator = this.eventCoordinators.get(key);
59
+ if (!coordinator) {
60
+ coordinator = new require_event_coordinator.EventCoordinator();
61
+ coordinator.onEmpty(() => this.eventCoordinators.delete(key));
62
+ this.eventCoordinators.set(key, coordinator);
63
+ }
64
+ return coordinator;
64
65
  }
65
66
  async handle(savedChange) {
66
- if (await this.shouldProceedAfterDebounce(savedChange) === false) return;
67
67
  const checkpointId = this.projection.getCheckpointId(savedChange);
68
+ const eventCoordinator = this.getEventCoordinator(checkpointId);
69
+ eventCoordinator.addEvent(savedChange);
70
+ await eventCoordinator.waitCurrentEvent();
71
+ if (!eventCoordinator.canProceed(savedChange)) {
72
+ eventCoordinator.cleanEvent(savedChange);
73
+ return;
74
+ }
75
+ const disposeEventCoordinator = eventCoordinator.start(savedChange);
68
76
  const target = await this.getCursor(savedChange);
69
- if (!target) throw new Error(`Cursor not found for event ${savedChange.id.serialize()}`);
77
+ if (!target) {
78
+ disposeEventCoordinator();
79
+ throw new Error(`Cursor not found for event ${savedChange.id.serialize()}`);
80
+ }
70
81
  const errors = [];
71
82
  for await (const [attempt, reset] of this.breathe()) {
72
83
  const source = this.projection.getSource(savedChange);
@@ -77,10 +88,12 @@ var FirestoreProjector = class {
77
88
  }
78
89
  if (status === Status.SUCCESS) {
79
90
  await this.queue.cleanup(checkpointId);
91
+ disposeEventCoordinator();
80
92
  return;
81
93
  }
82
94
  errors.push(message);
83
95
  }
96
+ disposeEventCoordinator();
84
97
  throw new Error(`Failed to handle event ${savedChange.id.serialize()}: ${errors.join(", ")}`);
85
98
  }
86
99
  async getCursor(savedChange) {
@@ -1,3 +1,4 @@
1
+ import { EventCoordinator } from "./event-coordinator.mjs";
1
2
  import { Cursor, EventId, Lock, ProjectedStreamReader } from "@ddd-ts/core";
2
3
  import { DefaultConverter } from "@ddd-ts/store-firestore";
3
4
  import { FieldValue, Timestamp } from "firebase-admin/firestore";
@@ -25,7 +26,6 @@ var FirestoreProjector = class {
25
26
  maxDelay: 200,
26
27
  backoff: 1.5
27
28
  },
28
- debounce: { delayMs: 0 },
29
29
  enqueue: { batchSize: 100 },
30
30
  onProcessError: (error) => {
31
31
  console.error("Error processing event:", error);
@@ -51,21 +51,32 @@ var FirestoreProjector = class {
51
51
  await wait((backoff * i + 1) * minDelay + jitter);
52
52
  }
53
53
  }
54
- checkpointTsTriggered = /* @__PURE__ */ new Map();
55
- async shouldProceedAfterDebounce(event) {
56
- const debounceDelay = this.config.debounce?.delayMs;
57
- if (!debounceDelay) return true;
58
- const checkpointId = this.projection.getCheckpointId(event).serialize();
59
- const currentTs = process.hrtime.bigint();
60
- this.checkpointTsTriggered.set(checkpointId, currentTs);
61
- await wait(debounceDelay);
62
- return this.checkpointTsTriggered.get(checkpointId) === currentTs;
54
+ eventCoordinators = /* @__PURE__ */ new Map();
55
+ getEventCoordinator(checkpointId) {
56
+ const key = checkpointId.serialize();
57
+ let coordinator = this.eventCoordinators.get(key);
58
+ if (!coordinator) {
59
+ coordinator = new EventCoordinator();
60
+ coordinator.onEmpty(() => this.eventCoordinators.delete(key));
61
+ this.eventCoordinators.set(key, coordinator);
62
+ }
63
+ return coordinator;
63
64
  }
64
65
  async handle(savedChange) {
65
- if (await this.shouldProceedAfterDebounce(savedChange) === false) return;
66
66
  const checkpointId = this.projection.getCheckpointId(savedChange);
67
+ const eventCoordinator = this.getEventCoordinator(checkpointId);
68
+ eventCoordinator.addEvent(savedChange);
69
+ await eventCoordinator.waitCurrentEvent();
70
+ if (!eventCoordinator.canProceed(savedChange)) {
71
+ eventCoordinator.cleanEvent(savedChange);
72
+ return;
73
+ }
74
+ const disposeEventCoordinator = eventCoordinator.start(savedChange);
67
75
  const target = await this.getCursor(savedChange);
68
- if (!target) throw new Error(`Cursor not found for event ${savedChange.id.serialize()}`);
76
+ if (!target) {
77
+ disposeEventCoordinator();
78
+ throw new Error(`Cursor not found for event ${savedChange.id.serialize()}`);
79
+ }
69
80
  const errors = [];
70
81
  for await (const [attempt, reset] of this.breathe()) {
71
82
  const source = this.projection.getSource(savedChange);
@@ -76,10 +87,12 @@ var FirestoreProjector = class {
76
87
  }
77
88
  if (status === Status.SUCCESS) {
78
89
  await this.queue.cleanup(checkpointId);
90
+ disposeEventCoordinator();
79
91
  return;
80
92
  }
81
93
  errors.push(message);
82
94
  }
95
+ disposeEventCoordinator();
83
96
  throw new Error(`Failed to handle event ${savedChange.id.serialize()}: ${errors.join(", ")}`);
84
97
  }
85
98
  async getCursor(savedChange) {
@@ -0,0 +1,7 @@
1
+ export interface PromiseResolvers<T> {
2
+ promise: Promise<T>;
3
+ resolve: (value: T) => void;
4
+ reject: (reason?: any) => void;
5
+ }
6
+ export declare const promiseWithResolvers: <T>() => PromiseResolvers<T>;
7
+ //# sourceMappingURL=promise-with-resolvers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promise-with-resolvers.d.ts","sourceRoot":"","sources":["../../src/utils/promise-with-resolvers.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;CAChC;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,OAAK,gBAAgB,CAAC,CAAC,CAQ5D,CAAC"}
@@ -0,0 +1,17 @@
1
+
2
+ //#region src/utils/promise-with-resolvers.ts
3
+ const promiseWithResolvers = () => {
4
+ let resolve;
5
+ let reject;
6
+ return {
7
+ promise: new Promise((res, rej) => {
8
+ resolve = res;
9
+ reject = rej;
10
+ }),
11
+ resolve,
12
+ reject
13
+ };
14
+ };
15
+
16
+ //#endregion
17
+ exports.promiseWithResolvers = promiseWithResolvers;
@@ -0,0 +1,16 @@
1
+ //#region src/utils/promise-with-resolvers.ts
2
+ const promiseWithResolvers = () => {
3
+ let resolve;
4
+ let reject;
5
+ return {
6
+ promise: new Promise((res, rej) => {
7
+ resolve = res;
8
+ reject = rej;
9
+ }),
10
+ resolve,
11
+ reject
12
+ };
13
+ };
14
+
15
+ //#endregion
16
+ export { promiseWithResolvers };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ddd-ts/event-sourcing-firestore",
3
- "version": "0.0.0-compute-timeout-on-process.9",
3
+ "version": "0.0.0-compute-timeout-on-process.11",
4
4
  "types": "dist/index.d.ts",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -10,19 +10,19 @@
10
10
  "dist"
11
11
  ],
12
12
  "dependencies": {
13
- "@ddd-ts/core": "0.0.0-compute-timeout-on-process.9",
14
- "@ddd-ts/shape": "0.0.0-compute-timeout-on-process.9",
15
- "@ddd-ts/store-firestore": "0.0.0-compute-timeout-on-process.9",
16
- "@ddd-ts/traits": "0.0.0-compute-timeout-on-process.9",
17
- "@ddd-ts/types": "0.0.0-compute-timeout-on-process.9",
13
+ "@ddd-ts/core": "0.0.0-compute-timeout-on-process.11",
14
+ "@ddd-ts/shape": "0.0.0-compute-timeout-on-process.11",
15
+ "@ddd-ts/store-firestore": "0.0.0-compute-timeout-on-process.11",
16
+ "@ddd-ts/traits": "0.0.0-compute-timeout-on-process.11",
17
+ "@ddd-ts/types": "0.0.0-compute-timeout-on-process.11",
18
18
  "@opentelemetry/api": "1.6.0",
19
19
  "firebase-admin": "^13.2.0"
20
20
  },
21
21
  "devDependencies": {
22
- "@ddd-ts/shape": "0.0.0-compute-timeout-on-process.9",
23
- "@ddd-ts/tests": "0.0.0-compute-timeout-on-process.9",
24
- "@ddd-ts/tools": "0.0.0-compute-timeout-on-process.9",
25
- "@ddd-ts/types": "0.0.0-compute-timeout-on-process.9",
22
+ "@ddd-ts/shape": "0.0.0-compute-timeout-on-process.11",
23
+ "@ddd-ts/tests": "0.0.0-compute-timeout-on-process.11",
24
+ "@ddd-ts/tools": "0.0.0-compute-timeout-on-process.11",
25
+ "@ddd-ts/types": "0.0.0-compute-timeout-on-process.11",
26
26
  "@types/jest": "^29.5.1"
27
27
  },
28
28
  "exports": {