abxbus 2.4.1 → 2.4.16
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.
- package/README.md +19 -7
- package/dist/cjs/base_event.d.ts +8 -4
- package/dist/cjs/base_event.js +98 -38
- package/dist/cjs/base_event.js.map +2 -2
- package/dist/cjs/event_bus.d.ts +0 -2
- package/dist/cjs/event_bus.js +13 -46
- package/dist/cjs/event_bus.js.map +2 -2
- package/dist/cjs/event_result.js +2 -2
- package/dist/cjs/event_result.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/lock_manager.d.ts +1 -1
- package/dist/cjs/lock_manager.js +9 -6
- package/dist/cjs/lock_manager.js.map +2 -2
- package/dist/cjs/logging.js +5 -2
- package/dist/cjs/logging.js.map +2 -2
- package/dist/cjs/middleware_otel_tracing.d.ts +28 -0
- package/dist/cjs/middleware_otel_tracing.js +189 -0
- package/dist/cjs/middleware_otel_tracing.js.map +7 -0
- package/dist/cjs/retry.d.ts +4 -1
- package/dist/cjs/retry.js +139 -12
- package/dist/cjs/retry.js.map +2 -2
- package/dist/esm/base_event.js +98 -38
- package/dist/esm/base_event.js.map +2 -2
- package/dist/esm/event_bus.js +13 -46
- package/dist/esm/event_bus.js.map +2 -2
- package/dist/esm/event_result.js +2 -2
- package/dist/esm/event_result.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/lock_manager.js +9 -6
- package/dist/esm/lock_manager.js.map +2 -2
- package/dist/esm/logging.js +6 -3
- package/dist/esm/logging.js.map +2 -2
- package/dist/esm/middleware_otel_tracing.js +169 -0
- package/dist/esm/middleware_otel_tracing.js.map +7 -0
- package/dist/esm/retry.js +139 -12
- package/dist/esm/retry.js.map +2 -2
- package/dist/types/base_event.d.ts +8 -4
- package/dist/types/event_bus.d.ts +0 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/lock_manager.d.ts +1 -1
- package/dist/types/middleware_otel_tracing.d.ts +28 -0
- package/dist/types/retry.d.ts +4 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
<img width="200" alt="image" src="https://github.com/user-attachments/assets/b3525c24-51ba-496c-b327-ccdfe46a7362" align="right" />
|
|
4
4
|
|
|
5
|
-
[](https://deepwiki.com/ArchiveBox/
|
|
5
|
+
[](https://deepwiki.com/ArchiveBox/abxbus) [](https://pypi.org/project/abxbus/) [](https://github.com/ArchiveBox/abxbus) 
|
|
6
6
|
|
|
7
|
-
[](https://deepwiki.com/ArchiveBox/
|
|
7
|
+
[](https://deepwiki.com/ArchiveBox/abxbus/3-typescript-implementation) [](https://www.npmjs.com/package/abxbus)
|
|
8
8
|
|
|
9
9
|
AbxBus is an in-memory event bus library for async Python and TS (node/bun/deno/browser).
|
|
10
10
|
|
|
@@ -27,17 +27,17 @@ It's async native, has proper automatic nested event tracking, and powerful conc
|
|
|
27
27
|
|
|
28
28
|
♾️ It's inspired by the simplicity of async and events in `JS` but with baked-in features that allow to eliminate most of the tedious repetitive complexity in event-driven codebases:
|
|
29
29
|
|
|
30
|
-
- correct timeout enforcement across multiple levels of events,
|
|
30
|
+
- correct timeout enforcement across multiple levels of events, including cancellation of awaited/blocking child work when a parent times out
|
|
31
31
|
- ability to strongly type hint and enforce the return type of event handlers at compile-time
|
|
32
32
|
- ability to queue events on the bus, or inline await them for immediate execution like a normal function call
|
|
33
33
|
- handles ~5,000 events/sec/core in both languages, with ~2kb/event RAM consumed per event during active processing
|
|
34
34
|
|
|
35
35
|
## 🔗 Links
|
|
36
36
|
|
|
37
|
-
- Issue Tracker: https://github.com/ArchiveBox/
|
|
37
|
+
- Issue Tracker: https://github.com/ArchiveBox/abxbus/issues
|
|
38
38
|
- Documentation: https://abxbus.archivebox.io
|
|
39
|
-
- DeepWiki: https://deepwiki.com/ArchiveBox/
|
|
40
|
-
- PyPI: https://pypi.org/project/
|
|
39
|
+
- DeepWiki: https://deepwiki.com/ArchiveBox/abxbus
|
|
40
|
+
- PyPI: https://pypi.org/project/abxbus/
|
|
41
41
|
- NPM: https://www.npmjs.com/package/abxbus
|
|
42
42
|
|
|
43
43
|
<br/>
|
|
@@ -294,6 +294,17 @@ await bus.waitUntilIdle() // this resolves once all three events have finished
|
|
|
294
294
|
await bus.waitUntilIdle(5) // wait up to 5 seconds, then continue even if work is still in-flight
|
|
295
295
|
```
|
|
296
296
|
|
|
297
|
+
#### Emit styles from handlers
|
|
298
|
+
|
|
299
|
+
Most handler code should use `await event.emit(ChildEvent({})).done()`. That creates a linked child and marks it as blocking parent completion.
|
|
300
|
+
|
|
301
|
+
| Style | `event_parent_id` | `event_blocks_parent_completion` | Blocks current handler? | Effect |
|
|
302
|
+
| --- | --- | --- | --- | --- |
|
|
303
|
+
| `await event.emit(ChildEvent({})).done()` | Parent event id | `true` | Yes | Linked child work; parent completion waits too. |
|
|
304
|
+
| `event.emit(ChildEvent({}))` without awaiting | Parent event id | `false` | No | Linked background child; visible in ancestry but parent completion does not wait. |
|
|
305
|
+
| `await bus.emit(TopLevelEvent({})).done()` | `null` | `false` | Yes | Detached top-level event; the handler waits naturally because it is awaited. |
|
|
306
|
+
| `bus.emit(TopLevelEvent({}))` without awaiting | `null` | `false` | No | True detached background event with no retained parent relationship. |
|
|
307
|
+
|
|
297
308
|
#### Parent/child/event lookup helpers
|
|
298
309
|
|
|
299
310
|
```ts
|
|
@@ -389,6 +400,7 @@ Special configuration fields you can set on each event to control processing:
|
|
|
389
400
|
- `event_path: string[]` (bus labels like `BusName#ab12`)
|
|
390
401
|
- `event_parent_id: string | null`
|
|
391
402
|
- `event_emitted_by_handler_id: string | null`
|
|
403
|
+
- `event_blocks_parent_completion: boolean`
|
|
392
404
|
- `event_status: 'pending' | 'started' | 'completed'`
|
|
393
405
|
- `event_results: Map<string, EventResult>`
|
|
394
406
|
- `event_pending_bus_count: number`
|
|
@@ -634,7 +646,7 @@ Notes:
|
|
|
634
646
|
## 👾 Development
|
|
635
647
|
|
|
636
648
|
```bash
|
|
637
|
-
git clone https://github.com/ArchiveBox/
|
|
649
|
+
git clone https://github.com/ArchiveBox/abxbus abxbus && cd abxbus
|
|
638
650
|
|
|
639
651
|
cd ./abxbus-ts
|
|
640
652
|
pnpm install
|
package/dist/cjs/base_event.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare const BaseEventSchema: z.ZodObject<{
|
|
|
14
14
|
event_slow_timeout: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
15
15
|
event_handler_timeout: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
16
16
|
event_handler_slow_timeout: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
17
|
+
event_blocks_parent_completion: z.ZodOptional<z.ZodBoolean>;
|
|
17
18
|
event_parent_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
18
19
|
event_path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
19
20
|
event_result_type: z.ZodOptional<z.ZodUnknown>;
|
|
@@ -43,7 +44,7 @@ export declare const BaseEventSchema: z.ZodObject<{
|
|
|
43
44
|
}, z.core.$loose>;
|
|
44
45
|
export type BaseEventData = z.infer<typeof BaseEventSchema>;
|
|
45
46
|
export type BaseEventJSON = BaseEventData & Record<string, unknown>;
|
|
46
|
-
type BaseEventFields = Pick<BaseEventData, 'event_id' | 'event_created_at' | 'event_type' | 'event_version' | 'event_timeout' | 'event_slow_timeout' | 'event_handler_timeout' | 'event_handler_slow_timeout' | 'event_parent_id' | 'event_path' | 'event_result_type' | 'event_emitted_by_handler_id' | 'event_pending_bus_count' | 'event_status' | 'event_started_at' | 'event_completed_at' | 'event_results' | 'event_concurrency' | 'event_handler_concurrency' | 'event_handler_completion'>;
|
|
47
|
+
type BaseEventFields = Pick<BaseEventData, 'event_id' | 'event_created_at' | 'event_type' | 'event_version' | 'event_timeout' | 'event_slow_timeout' | 'event_handler_timeout' | 'event_handler_slow_timeout' | 'event_blocks_parent_completion' | 'event_parent_id' | 'event_path' | 'event_result_type' | 'event_emitted_by_handler_id' | 'event_pending_bus_count' | 'event_status' | 'event_started_at' | 'event_completed_at' | 'event_results' | 'event_concurrency' | 'event_handler_concurrency' | 'event_handler_completion'>;
|
|
47
48
|
export type BaseEventInit<TFields extends Record<string, unknown>> = TFields & Partial<BaseEventFields>;
|
|
48
49
|
type BaseEventSchemaShape = typeof BaseEventSchema.shape;
|
|
49
50
|
export type EventSchema<TShape extends z.ZodRawShape> = z.ZodObject<BaseEventSchemaShape & TShape>;
|
|
@@ -95,6 +96,7 @@ export declare class BaseEvent {
|
|
|
95
96
|
event_slow_timeout?: number | null;
|
|
96
97
|
event_handler_timeout?: number | null;
|
|
97
98
|
event_handler_slow_timeout?: number | null;
|
|
99
|
+
event_blocks_parent_completion: boolean;
|
|
98
100
|
event_parent_id: string | null;
|
|
99
101
|
event_path: string[];
|
|
100
102
|
event_result_type?: z.ZodTypeAny;
|
|
@@ -118,6 +120,7 @@ export declare class BaseEvent {
|
|
|
118
120
|
event_slow_timeout: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
119
121
|
event_handler_timeout: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
120
122
|
event_handler_slow_timeout: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
123
|
+
event_blocks_parent_completion: z.ZodOptional<z.ZodBoolean>;
|
|
121
124
|
event_parent_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
122
125
|
event_path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
123
126
|
event_result_type: z.ZodOptional<z.ZodUnknown>;
|
|
@@ -145,12 +148,11 @@ export declare class BaseEvent {
|
|
|
145
148
|
first: "first";
|
|
146
149
|
}>>>;
|
|
147
150
|
}, z.core.$loose>;
|
|
148
|
-
|
|
151
|
+
event_bus?: EventBus;
|
|
149
152
|
_event_original?: BaseEvent;
|
|
150
153
|
_event_dispatch_context?: unknown | null;
|
|
151
154
|
_event_completed_signal: Deferred<this> | null;
|
|
152
155
|
_lock_for_event_handler: AsyncLock | null;
|
|
153
|
-
get event_bus(): EventBus;
|
|
154
156
|
constructor(data?: BaseEventInit<Record<string, unknown>>);
|
|
155
157
|
toString(): string;
|
|
156
158
|
static extend<TShape extends z.ZodRawShape>(event_type: string, shape?: TShape): EventFactory<TShape, ResultSchemaFromShape<TShape>>;
|
|
@@ -180,6 +182,7 @@ export declare class BaseEvent {
|
|
|
180
182
|
get event_parent(): BaseEvent | undefined;
|
|
181
183
|
get event_children(): BaseEvent[];
|
|
182
184
|
get event_descendants(): BaseEvent[];
|
|
185
|
+
emit<T extends BaseEvent>(event: T): T;
|
|
183
186
|
_cancelPendingChildProcessing(reason: unknown): void;
|
|
184
187
|
_markRemainingFirstModeResultCancelled(winner: EventResult): void;
|
|
185
188
|
_markCancelled(cause: Error): void;
|
|
@@ -189,6 +192,7 @@ export declare class BaseEvent {
|
|
|
189
192
|
eventResultsList(include: EventResultsListInclude<this>, options?: EventResultsListOptions<this>): Promise<Array<EventResultType<this> | undefined>>;
|
|
190
193
|
eventResultsList(options?: EventResultsListOptions<this>): Promise<Array<EventResultType<this> | undefined>>;
|
|
191
194
|
eventCompleted(): Promise<this>;
|
|
195
|
+
_markBlocksParentCompletionIfAwaitedFromEmittingHandler(): void;
|
|
192
196
|
_markPending(): this;
|
|
193
197
|
eventReset(): this;
|
|
194
198
|
_markStarted(started_at?: string | null, notify_hook?: boolean): void;
|
|
@@ -200,7 +204,7 @@ export declare class BaseEvent {
|
|
|
200
204
|
ignore_first_mode_control_errors?: boolean;
|
|
201
205
|
}): unknown | undefined;
|
|
202
206
|
get event_result(): EventResultType<this> | undefined;
|
|
203
|
-
_areAllChildrenComplete(): boolean;
|
|
207
|
+
_areAllChildrenComplete(visited?: Set<string>): boolean;
|
|
204
208
|
private _notifyDoneListeners;
|
|
205
209
|
_gc(): void;
|
|
206
210
|
}
|
package/dist/cjs/base_event.js
CHANGED
|
@@ -30,7 +30,7 @@ var import_lock_manager = require("./lock_manager.js");
|
|
|
30
30
|
var import_timing = require("./timing.js");
|
|
31
31
|
var import_types = require("./types.js");
|
|
32
32
|
var import_helpers = require("./helpers.js");
|
|
33
|
-
const RESERVED_USER_EVENT_FIELDS = /* @__PURE__ */ new Set(["bus", "first", "toString", "toJSON", "fromJSON"]);
|
|
33
|
+
const RESERVED_USER_EVENT_FIELDS = /* @__PURE__ */ new Set(["bus", "emit", "first", "toString", "toJSON", "fromJSON"]);
|
|
34
34
|
function assertNoReservedUserEventFields(data, context) {
|
|
35
35
|
for (const field_name of RESERVED_USER_EVENT_FIELDS) {
|
|
36
36
|
if (Object.prototype.hasOwnProperty.call(data, field_name)) {
|
|
@@ -69,6 +69,7 @@ const BaseEventSchema = import_zod.z.object({
|
|
|
69
69
|
event_slow_timeout: import_zod.z.number().positive().nullable().optional(),
|
|
70
70
|
event_handler_timeout: import_zod.z.number().positive().nullable().optional(),
|
|
71
71
|
event_handler_slow_timeout: import_zod.z.number().positive().nullable().optional(),
|
|
72
|
+
event_blocks_parent_completion: import_zod.z.boolean().optional(),
|
|
72
73
|
event_parent_id: import_zod.z.string().uuid().nullable().optional(),
|
|
73
74
|
event_path: import_zod.z.array(import_zod.z.string()).optional(),
|
|
74
75
|
event_result_type: import_zod.z.unknown().optional(),
|
|
@@ -102,6 +103,8 @@ class BaseEvent {
|
|
|
102
103
|
// optional per-event handler timeout override in seconds
|
|
103
104
|
event_handler_slow_timeout;
|
|
104
105
|
// optional per-event slow handler warning threshold in seconds
|
|
106
|
+
event_blocks_parent_completion;
|
|
107
|
+
// true only for children explicitly awaited via done()/eventCompleted()
|
|
105
108
|
event_parent_id;
|
|
106
109
|
// id of the parent event that triggered this event, if this event was emitted during handling of another event, else null
|
|
107
110
|
event_path;
|
|
@@ -130,17 +133,14 @@ class BaseEvent {
|
|
|
130
133
|
static schema = BaseEventSchema;
|
|
131
134
|
// zod schema for the event data fields, used to parse and validate event data when creating a new event
|
|
132
135
|
// internal runtime state
|
|
133
|
-
|
|
134
|
-
//
|
|
136
|
+
event_bus;
|
|
137
|
+
// bus that dispatched this event, also used by event.emit(child)
|
|
135
138
|
_event_original;
|
|
136
139
|
// underlying event object that was dispatched, if this is a bus-scoped proxy wrapping it
|
|
137
140
|
_event_dispatch_context;
|
|
138
141
|
// captured AsyncLocalStorage context at dispatch site, used to restore that context when running handlers
|
|
139
142
|
_event_completed_signal;
|
|
140
143
|
_lock_for_event_handler;
|
|
141
|
-
get event_bus() {
|
|
142
|
-
return this.bus;
|
|
143
|
-
}
|
|
144
144
|
constructor(data = {}) {
|
|
145
145
|
assertNoReservedUserEventFields(data, "BaseEvent");
|
|
146
146
|
assertNoUnknownEventPrefixedFields(data, "BaseEvent");
|
|
@@ -158,6 +158,7 @@ class BaseEvent {
|
|
|
158
158
|
const event_id = merged_data.event_id ?? (0, import_uuid.v7)();
|
|
159
159
|
const event_created_at = (0, import_helpers.monotonicDatetime)(merged_data.event_created_at);
|
|
160
160
|
const event_timeout = merged_data.event_timeout ?? null;
|
|
161
|
+
const event_blocks_parent_completion = merged_data.event_blocks_parent_completion ?? false;
|
|
161
162
|
const base_data = {
|
|
162
163
|
...merged_data,
|
|
163
164
|
event_id,
|
|
@@ -165,6 +166,7 @@ class BaseEvent {
|
|
|
165
166
|
event_type,
|
|
166
167
|
event_version,
|
|
167
168
|
event_timeout,
|
|
169
|
+
event_blocks_parent_completion,
|
|
168
170
|
event_result_type
|
|
169
171
|
};
|
|
170
172
|
const schema = ctor.schema ?? BaseEventSchema;
|
|
@@ -253,7 +255,7 @@ class BaseEvent {
|
|
|
253
255
|
toJSON() {
|
|
254
256
|
const record = {};
|
|
255
257
|
for (const [key, value] of Object.entries(this)) {
|
|
256
|
-
if (key.startsWith("_") || key === "bus" || key === "event_results") continue;
|
|
258
|
+
if (key.startsWith("_") || key === "bus" || key === "event_bus" || key === "event_results") continue;
|
|
257
259
|
if (value === void 0 || typeof value === "function") continue;
|
|
258
260
|
record[key] = value;
|
|
259
261
|
}
|
|
@@ -272,6 +274,7 @@ class BaseEvent {
|
|
|
272
274
|
event_handler_completion: this.event_handler_completion,
|
|
273
275
|
event_handler_slow_timeout: this.event_handler_slow_timeout,
|
|
274
276
|
event_handler_timeout: this.event_handler_timeout,
|
|
277
|
+
event_blocks_parent_completion: this.event_blocks_parent_completion,
|
|
275
278
|
// mutable parent/child/bus tracking runtime state
|
|
276
279
|
event_parent_id: this.event_parent_id,
|
|
277
280
|
event_path: this.event_path,
|
|
@@ -287,12 +290,12 @@ class BaseEvent {
|
|
|
287
290
|
};
|
|
288
291
|
}
|
|
289
292
|
_createSlowEventWarningTimer() {
|
|
290
|
-
const event_slow_timeout = this.event_slow_timeout ?? this.
|
|
293
|
+
const event_slow_timeout = this.event_slow_timeout ?? this.event_bus?.event_slow_timeout ?? null;
|
|
291
294
|
const event_warn_ms = event_slow_timeout === null ? null : event_slow_timeout * 1e3;
|
|
292
295
|
if (event_warn_ms === null) {
|
|
293
296
|
return null;
|
|
294
297
|
}
|
|
295
|
-
const name = this.
|
|
298
|
+
const name = this.event_bus?.name ?? "EventBus";
|
|
296
299
|
return setTimeout(() => {
|
|
297
300
|
if (this.event_status === "completed") {
|
|
298
301
|
return;
|
|
@@ -312,8 +315,8 @@ class BaseEvent {
|
|
|
312
315
|
let handler_entry;
|
|
313
316
|
if (handler instanceof import_event_handler.EventHandler) {
|
|
314
317
|
handler_entry = handler;
|
|
315
|
-
if (!resolved_eventbus && handler_entry.eventbus_id !== ROOT_EVENTBUS_ID && original_event.
|
|
316
|
-
resolved_eventbus = original_event.
|
|
318
|
+
if (!resolved_eventbus && handler_entry.eventbus_id !== ROOT_EVENTBUS_ID && original_event.event_bus) {
|
|
319
|
+
resolved_eventbus = original_event.event_bus.all_instances.findBusById(handler_entry.eventbus_id) ?? (original_event.event_bus.id === handler_entry.eventbus_id ? original_event.event_bus : void 0);
|
|
317
320
|
}
|
|
318
321
|
} else {
|
|
319
322
|
handler_entry = import_event_handler.EventHandler.fromCallable({
|
|
@@ -372,10 +375,10 @@ class BaseEvent {
|
|
|
372
375
|
if (pending_entries) {
|
|
373
376
|
return pending_entries.map((entry) => entry.result);
|
|
374
377
|
}
|
|
375
|
-
if (!this.
|
|
378
|
+
if (!this.event_bus?.id) {
|
|
376
379
|
return Array.from(original.event_results.values());
|
|
377
380
|
}
|
|
378
|
-
return Array.from(original.event_results.values()).filter((result) => result.eventbus_id === this.
|
|
381
|
+
return Array.from(original.event_results.values()).filter((result) => result.eventbus_id === this.event_bus.id);
|
|
379
382
|
}
|
|
380
383
|
_isFirstModeWinningResult(entry) {
|
|
381
384
|
return entry.status === "completed" && entry.result !== void 0 && entry.result !== null && !(entry.result instanceof BaseEvent);
|
|
@@ -388,10 +391,10 @@ class BaseEvent {
|
|
|
388
391
|
original._markRemainingFirstModeResultCancelled(entry);
|
|
389
392
|
}
|
|
390
393
|
async _runHandlerWithLock(original, entry) {
|
|
391
|
-
if (!this.
|
|
394
|
+
if (!this.event_bus) {
|
|
392
395
|
throw new Error("event has no bus attached");
|
|
393
396
|
}
|
|
394
|
-
await this.
|
|
397
|
+
await this.event_bus.locks._runWithHandlerLock(original, this.event_bus.event_handler_concurrency, async (handler_lock) => {
|
|
395
398
|
await entry.runHandler(handler_lock);
|
|
396
399
|
});
|
|
397
400
|
}
|
|
@@ -402,9 +405,9 @@ class BaseEvent {
|
|
|
402
405
|
if (pending_results.length === 0) {
|
|
403
406
|
return;
|
|
404
407
|
}
|
|
405
|
-
const resolved_completion = original.event_handler_completion ?? this.
|
|
408
|
+
const resolved_completion = original.event_handler_completion ?? this.event_bus?.event_handler_completion ?? "all";
|
|
406
409
|
if (resolved_completion === "first") {
|
|
407
|
-
if (original._getHandlerLock(this.
|
|
410
|
+
if (original._getHandlerLock(this.event_bus?.event_handler_concurrency) !== null) {
|
|
408
411
|
for (const entry of pending_results) {
|
|
409
412
|
await this._runHandlerWithLock(original, entry);
|
|
410
413
|
if (!this._isFirstModeWinningResult(entry)) {
|
|
@@ -431,7 +434,7 @@ class BaseEvent {
|
|
|
431
434
|
}
|
|
432
435
|
_getHandlerLock(default_concurrency) {
|
|
433
436
|
const original = this._event_original ?? this;
|
|
434
|
-
const resolved = original.event_handler_concurrency ?? default_concurrency ?? original.
|
|
437
|
+
const resolved = original.event_handler_concurrency ?? default_concurrency ?? original.event_bus?.event_handler_concurrency ?? "serial";
|
|
435
438
|
if (resolved === "parallel") {
|
|
436
439
|
return null;
|
|
437
440
|
}
|
|
@@ -459,7 +462,7 @@ class BaseEvent {
|
|
|
459
462
|
if (!parent_id) {
|
|
460
463
|
return void 0;
|
|
461
464
|
}
|
|
462
|
-
return original.
|
|
465
|
+
return original.event_bus?.findEventById(parent_id) ?? void 0;
|
|
463
466
|
}
|
|
464
467
|
// get all direct children of this event
|
|
465
468
|
get event_children() {
|
|
@@ -501,6 +504,17 @@ class BaseEvent {
|
|
|
501
504
|
}
|
|
502
505
|
return descendants;
|
|
503
506
|
}
|
|
507
|
+
emit(event) {
|
|
508
|
+
const original_parent = this._event_original ?? this;
|
|
509
|
+
const original_child = event._event_original ?? event;
|
|
510
|
+
if (!original_child.event_parent_id && original_child.event_id !== original_parent.event_id) {
|
|
511
|
+
original_child.event_parent_id = original_parent.event_id;
|
|
512
|
+
}
|
|
513
|
+
if (!this.event_bus) {
|
|
514
|
+
throw new Error("event has no bus attached");
|
|
515
|
+
}
|
|
516
|
+
return this.event_bus.emit(original_child);
|
|
517
|
+
}
|
|
504
518
|
// force-abort processing of all pending descendants of an event regardless of whether they have already started
|
|
505
519
|
_cancelPendingChildProcessing(reason) {
|
|
506
520
|
const original = this._event_original ?? this;
|
|
@@ -513,6 +527,10 @@ class BaseEvent {
|
|
|
513
527
|
}
|
|
514
528
|
visited.add(original_child.event_id);
|
|
515
529
|
for (const grandchild of original_child.event_children) {
|
|
530
|
+
const original_grandchild = grandchild._event_original ?? grandchild;
|
|
531
|
+
if (!original_grandchild.event_blocks_parent_completion) {
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
516
534
|
cancelChildEvent(grandchild);
|
|
517
535
|
}
|
|
518
536
|
original_child._markCancelled(cancellation_cause);
|
|
@@ -521,6 +539,10 @@ class BaseEvent {
|
|
|
521
539
|
}
|
|
522
540
|
};
|
|
523
541
|
for (const child of original.event_children) {
|
|
542
|
+
const original_child = child._event_original ?? child;
|
|
543
|
+
if (!original_child.event_blocks_parent_completion) {
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
524
546
|
cancelChildEvent(child);
|
|
525
547
|
}
|
|
526
548
|
}
|
|
@@ -543,6 +565,9 @@ class BaseEvent {
|
|
|
543
565
|
} else if (result.status === "started") {
|
|
544
566
|
for (const child of result.event_children) {
|
|
545
567
|
const original_child = child._event_original ?? child;
|
|
568
|
+
if (!original_child.event_blocks_parent_completion) {
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
546
571
|
original_child._cancelPendingChildProcessing(cause);
|
|
547
572
|
original_child._markCancelled(cause);
|
|
548
573
|
}
|
|
@@ -559,7 +584,7 @@ class BaseEvent {
|
|
|
559
584
|
// force-abort processing of this event regardless of whether it is pending or has already started
|
|
560
585
|
_markCancelled(cause) {
|
|
561
586
|
const original = this._event_original ?? this;
|
|
562
|
-
if (!this.
|
|
587
|
+
if (!this.event_bus) {
|
|
563
588
|
if (original.event_status !== "completed") {
|
|
564
589
|
original._markCompleted();
|
|
565
590
|
}
|
|
@@ -567,7 +592,7 @@ class BaseEvent {
|
|
|
567
592
|
}
|
|
568
593
|
const path = Array.isArray(original.event_path) ? original.event_path : [];
|
|
569
594
|
const buses_to_cancel = new Set(path);
|
|
570
|
-
for (const bus of this.
|
|
595
|
+
for (const bus of this.event_bus.all_instances) {
|
|
571
596
|
if (!buses_to_cancel.has(bus.label)) {
|
|
572
597
|
continue;
|
|
573
598
|
}
|
|
@@ -606,14 +631,14 @@ class BaseEvent {
|
|
|
606
631
|
}
|
|
607
632
|
_notifyEventParentsOfCompletion() {
|
|
608
633
|
const original = this._event_original ?? this;
|
|
609
|
-
if (!this.
|
|
634
|
+
if (!this.event_bus) {
|
|
610
635
|
return;
|
|
611
636
|
}
|
|
612
637
|
const visited = /* @__PURE__ */ new Set();
|
|
613
638
|
let parent_id = original.event_parent_id;
|
|
614
639
|
while (parent_id && !visited.has(parent_id)) {
|
|
615
640
|
visited.add(parent_id);
|
|
616
|
-
const parent = this.
|
|
641
|
+
const parent = this.event_bus.findEventById(parent_id);
|
|
617
642
|
if (!parent) {
|
|
618
643
|
break;
|
|
619
644
|
}
|
|
@@ -627,12 +652,13 @@ class BaseEvent {
|
|
|
627
652
|
// awaitable that triggers immediate (queue-jump) processing of the event on all buses where it is queued
|
|
628
653
|
// use eventCompleted() to wait for normal queue-order completion without queue-jumping.
|
|
629
654
|
done(options = {}) {
|
|
630
|
-
if (!this.
|
|
655
|
+
if (!this.event_bus) {
|
|
631
656
|
return Promise.reject(new Error("event has no bus attached"));
|
|
632
657
|
}
|
|
633
658
|
const original = this._event_original ?? this;
|
|
659
|
+
original._markBlocksParentCompletionIfAwaitedFromEmittingHandler();
|
|
634
660
|
const raise_if_any = options.raise_if_any ?? true;
|
|
635
|
-
const completion_promise = this.event_status === "completed" ? Promise.resolve(original) : this.
|
|
661
|
+
const completion_promise = this.event_status === "completed" ? Promise.resolve(original) : this.event_bus._processEventImmediately(this);
|
|
636
662
|
if (!raise_if_any) {
|
|
637
663
|
return completion_promise;
|
|
638
664
|
}
|
|
@@ -652,7 +678,7 @@ class BaseEvent {
|
|
|
652
678
|
// parallel: races all handlers, returns first non-undefined, aborts the rest
|
|
653
679
|
// serial: runs handlers sequentially, returns first non-undefined, skips remaining
|
|
654
680
|
first() {
|
|
655
|
-
if (!this.
|
|
681
|
+
if (!this.event_bus) {
|
|
656
682
|
return Promise.reject(new Error("event has no bus attached"));
|
|
657
683
|
}
|
|
658
684
|
const original = this._event_original ?? this;
|
|
@@ -685,7 +711,7 @@ class BaseEvent {
|
|
|
685
711
|
const raise_if_any = options.raise_if_any ?? true;
|
|
686
712
|
const raise_if_none = options.raise_if_none ?? true;
|
|
687
713
|
const original = this._event_original ?? this;
|
|
688
|
-
const resolved_timeout_seconds = options.timeout ?? original.event_timeout ?? this.
|
|
714
|
+
const resolved_timeout_seconds = options.timeout ?? original.event_timeout ?? this.event_bus?.event_timeout ?? null;
|
|
689
715
|
let completed_event;
|
|
690
716
|
if (resolved_timeout_seconds === null) {
|
|
691
717
|
completed_event = await this.done({ raise_if_any: false });
|
|
@@ -733,12 +759,29 @@ class BaseEvent {
|
|
|
733
759
|
}
|
|
734
760
|
// awaitable that waits for the event to be processed in normal queue order by the _runloop
|
|
735
761
|
eventCompleted() {
|
|
762
|
+
const original = this._event_original ?? this;
|
|
763
|
+
original._markBlocksParentCompletionIfAwaitedFromEmittingHandler();
|
|
736
764
|
if (this.event_status === "completed") {
|
|
737
765
|
return Promise.resolve(this);
|
|
738
766
|
}
|
|
739
767
|
this._notifyDoneListeners();
|
|
740
768
|
return this._event_completed_signal.promise;
|
|
741
769
|
}
|
|
770
|
+
_markBlocksParentCompletionIfAwaitedFromEmittingHandler() {
|
|
771
|
+
const original = this._event_original ?? this;
|
|
772
|
+
if (original.event_blocks_parent_completion || !original.event_bus) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
const active_result = original.event_bus.locks._getActiveHandlerResultForCurrentAsyncContext();
|
|
776
|
+
if (!active_result || active_result.status !== "started") {
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
const active_parent = active_result.event._event_original ?? active_result.event;
|
|
780
|
+
const is_child_of_active_handler = original.event_parent_id === active_parent.event_id && original.event_emitted_by_handler_id === active_result.handler_id && active_result.event_children.some((child) => (child._event_original ?? child).event_id === original.event_id);
|
|
781
|
+
if (is_child_of_active_handler) {
|
|
782
|
+
original.event_blocks_parent_completion = true;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
742
785
|
_markPending() {
|
|
743
786
|
const original = this._event_original ?? this;
|
|
744
787
|
original.event_status = "pending";
|
|
@@ -749,7 +792,7 @@ class BaseEvent {
|
|
|
749
792
|
original._setDispatchContext(void 0);
|
|
750
793
|
original._event_completed_signal = null;
|
|
751
794
|
original._lock_for_event_handler = null;
|
|
752
|
-
original.
|
|
795
|
+
original.event_bus = void 0;
|
|
753
796
|
return this;
|
|
754
797
|
}
|
|
755
798
|
eventReset() {
|
|
@@ -766,8 +809,8 @@ class BaseEvent {
|
|
|
766
809
|
}
|
|
767
810
|
original.event_status = "started";
|
|
768
811
|
original.event_started_at = started_at === null ? (0, import_helpers.monotonicDatetime)() : (0, import_helpers.monotonicDatetime)(started_at);
|
|
769
|
-
if (notify_hook && original.
|
|
770
|
-
const bus_for_hook = original.
|
|
812
|
+
if (notify_hook && original.event_bus) {
|
|
813
|
+
const bus_for_hook = original.event_bus;
|
|
771
814
|
const event_for_bus = bus_for_hook._getEventProxyScopedToThisBus(original);
|
|
772
815
|
void bus_for_hook.onEventChange(event_for_bus, "started");
|
|
773
816
|
}
|
|
@@ -787,8 +830,8 @@ class BaseEvent {
|
|
|
787
830
|
}
|
|
788
831
|
original.event_status = "completed";
|
|
789
832
|
original.event_completed_at = (0, import_helpers.monotonicDatetime)();
|
|
790
|
-
if (original.
|
|
791
|
-
const bus_for_hook = original.
|
|
833
|
+
if (original.event_bus) {
|
|
834
|
+
const bus_for_hook = original.event_bus;
|
|
792
835
|
const event_for_bus = bus_for_hook._getEventProxyScopedToThisBus(original);
|
|
793
836
|
void bus_for_hook.onEventChange(event_for_bus, "completed");
|
|
794
837
|
}
|
|
@@ -797,16 +840,16 @@ class BaseEvent {
|
|
|
797
840
|
original._event_completed_signal.resolve(original);
|
|
798
841
|
original._event_completed_signal = null;
|
|
799
842
|
original.dropFromZeroHistoryBuses();
|
|
800
|
-
if (notify_parents && original.
|
|
843
|
+
if (notify_parents && original.event_bus) {
|
|
801
844
|
original._notifyEventParentsOfCompletion();
|
|
802
845
|
}
|
|
803
846
|
}
|
|
804
847
|
dropFromZeroHistoryBuses() {
|
|
805
|
-
if (!this.
|
|
848
|
+
if (!this.event_bus) {
|
|
806
849
|
return;
|
|
807
850
|
}
|
|
808
851
|
const original = this._event_original ?? this;
|
|
809
|
-
for (const bus of this.
|
|
852
|
+
for (const bus of this.event_bus.all_instances) {
|
|
810
853
|
if (bus.event_history.max_history_size !== 0) {
|
|
811
854
|
continue;
|
|
812
855
|
}
|
|
@@ -834,8 +877,25 @@ class BaseEvent {
|
|
|
834
877
|
get event_result() {
|
|
835
878
|
return Array.from(this.event_results.values()).filter((event_result) => event_result.completed_at !== null && event_result.result !== void 0).sort((event_result_a, event_result_b) => compareIsoDatetime(event_result_a.completed_at, event_result_b.completed_at)).map((event_result) => event_result.result).at(0);
|
|
836
879
|
}
|
|
837
|
-
_areAllChildrenComplete() {
|
|
838
|
-
|
|
880
|
+
_areAllChildrenComplete(visited = /* @__PURE__ */ new Set()) {
|
|
881
|
+
const original = this._event_original ?? this;
|
|
882
|
+
if (visited.has(original.event_id)) {
|
|
883
|
+
return true;
|
|
884
|
+
}
|
|
885
|
+
visited.add(original.event_id);
|
|
886
|
+
for (const child of original.event_children) {
|
|
887
|
+
const original_child = child._event_original ?? child;
|
|
888
|
+
if (!original_child.event_blocks_parent_completion) {
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
if (original_child.event_status !== "completed") {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
if (!original_child._areAllChildrenComplete(visited)) {
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return true;
|
|
839
899
|
}
|
|
840
900
|
_notifyDoneListeners() {
|
|
841
901
|
if (this._event_completed_signal) {
|
|
@@ -848,7 +908,7 @@ class BaseEvent {
|
|
|
848
908
|
_gc() {
|
|
849
909
|
this._event_completed_signal = null;
|
|
850
910
|
this._setDispatchContext(null);
|
|
851
|
-
this.
|
|
911
|
+
this.event_bus = void 0;
|
|
852
912
|
this._lock_for_event_handler = null;
|
|
853
913
|
for (const result of this.event_results.values()) {
|
|
854
914
|
result.event_children = [];
|