bubus 1.8.1 → 2.2.1
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 +510 -75
- package/dist/esm/async_context.js +39 -0
- package/dist/esm/async_context.js.map +7 -0
- package/dist/esm/base_event.js +825 -0
- package/dist/esm/base_event.js.map +7 -0
- package/dist/esm/bridge_jsonl.js +150 -0
- package/dist/esm/bridge_jsonl.js.map +7 -0
- package/dist/esm/bridge_nats.js +88 -0
- package/dist/esm/bridge_nats.js.map +7 -0
- package/dist/esm/bridge_postgres.js +231 -0
- package/dist/esm/bridge_postgres.js.map +7 -0
- package/dist/esm/bridge_redis.js +155 -0
- package/dist/esm/bridge_redis.js.map +7 -0
- package/dist/esm/bridge_sqlite.js +235 -0
- package/dist/esm/bridge_sqlite.js.map +7 -0
- package/dist/esm/bridges.js +306 -0
- package/dist/esm/bridges.js.map +7 -0
- package/dist/esm/event_bus.js +1046 -0
- package/dist/esm/event_bus.js.map +7 -0
- package/dist/esm/event_handler.js +279 -0
- package/dist/esm/event_handler.js.map +7 -0
- package/dist/esm/event_history.js +172 -0
- package/dist/esm/event_history.js.map +7 -0
- package/dist/esm/event_result.js +426 -0
- package/dist/esm/event_result.js.map +7 -0
- package/dist/esm/events_suck.js +39 -0
- package/dist/esm/events_suck.js.map +7 -0
- package/dist/esm/helpers.js +64 -0
- package/dist/esm/helpers.js.map +7 -0
- package/dist/esm/index.js +32 -16559
- package/dist/esm/index.js.map +4 -4
- package/dist/esm/lock_manager.js +323 -0
- package/dist/esm/lock_manager.js.map +7 -0
- package/dist/esm/logging.js +196 -0
- package/dist/esm/logging.js.map +7 -0
- package/dist/esm/middlewares.js +1 -0
- package/dist/esm/middlewares.js.map +7 -0
- package/dist/esm/optional_deps.js +34 -0
- package/dist/esm/optional_deps.js.map +7 -0
- package/dist/esm/retry.js +237 -0
- package/dist/esm/retry.js.map +7 -0
- package/dist/esm/timing.js +56 -0
- package/dist/esm/timing.js.map +7 -0
- package/dist/esm/types.js +84 -0
- package/dist/esm/types.js.map +7 -0
- package/dist/types/async_context.d.ts +1 -1
- package/dist/types/base_event.d.ts +96 -79
- package/dist/types/bridge_jsonl.d.ts +26 -0
- package/dist/types/bridge_nats.d.ts +20 -0
- package/dist/types/bridge_postgres.d.ts +31 -0
- package/dist/types/bridge_redis.d.ts +34 -0
- package/dist/types/bridge_sqlite.d.ts +30 -0
- package/dist/types/bridges.d.ts +49 -0
- package/dist/types/event_bus.d.ts +88 -41
- package/dist/types/event_handler.d.ts +47 -18
- package/dist/types/event_history.d.ts +45 -0
- package/dist/types/event_result.d.ts +37 -33
- package/dist/types/events_suck.d.ts +40 -0
- package/dist/types/helpers.d.ts +1 -0
- package/dist/types/index.d.ts +10 -1
- package/dist/types/lock_manager.d.ts +27 -18
- package/dist/types/logging.d.ts +4 -1
- package/dist/types/middlewares.d.ts +13 -0
- package/dist/types/optional_deps.d.ts +3 -0
- package/dist/types/timing.d.ts +3 -0
- package/dist/types/types.d.ts +18 -7
- package/package.json +25 -11
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { normalizeEventPattern } from "./types.js";
|
|
2
|
+
import { monotonicDatetime } from "./helpers.js";
|
|
3
|
+
class EventHistory {
|
|
4
|
+
max_history_size;
|
|
5
|
+
max_history_drop;
|
|
6
|
+
_events;
|
|
7
|
+
_warned_about_dropping_uncompleted_events;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.max_history_size = options.max_history_size === void 0 ? 100 : options.max_history_size;
|
|
10
|
+
this.max_history_drop = options.max_history_drop ?? false;
|
|
11
|
+
this._events = /* @__PURE__ */ new Map();
|
|
12
|
+
this._warned_about_dropping_uncompleted_events = false;
|
|
13
|
+
}
|
|
14
|
+
get size() {
|
|
15
|
+
return this._events.size;
|
|
16
|
+
}
|
|
17
|
+
[Symbol.iterator]() {
|
|
18
|
+
return this._events[Symbol.iterator]();
|
|
19
|
+
}
|
|
20
|
+
entries() {
|
|
21
|
+
return this._events.entries();
|
|
22
|
+
}
|
|
23
|
+
keys() {
|
|
24
|
+
return this._events.keys();
|
|
25
|
+
}
|
|
26
|
+
values() {
|
|
27
|
+
return this._events.values();
|
|
28
|
+
}
|
|
29
|
+
clear() {
|
|
30
|
+
this._events.clear();
|
|
31
|
+
}
|
|
32
|
+
get(event_id) {
|
|
33
|
+
return this._events.get(event_id);
|
|
34
|
+
}
|
|
35
|
+
set(event_id, event) {
|
|
36
|
+
this._events.set(event_id, event);
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
has(event_id) {
|
|
40
|
+
return this._events.has(event_id);
|
|
41
|
+
}
|
|
42
|
+
delete(event_id) {
|
|
43
|
+
return this._events.delete(event_id);
|
|
44
|
+
}
|
|
45
|
+
addEvent(event) {
|
|
46
|
+
this._events.set(event.event_id, event);
|
|
47
|
+
}
|
|
48
|
+
getEvent(event_id) {
|
|
49
|
+
return this._events.get(event_id);
|
|
50
|
+
}
|
|
51
|
+
removeEvent(event_id) {
|
|
52
|
+
return this._events.delete(event_id);
|
|
53
|
+
}
|
|
54
|
+
hasEvent(event_id) {
|
|
55
|
+
return this._events.has(event_id);
|
|
56
|
+
}
|
|
57
|
+
static normalizeEventPattern(event_pattern) {
|
|
58
|
+
return normalizeEventPattern(event_pattern);
|
|
59
|
+
}
|
|
60
|
+
async find(event_pattern, where = () => true, options = {}) {
|
|
61
|
+
const past = options.past ?? true;
|
|
62
|
+
const future = options.future ?? false;
|
|
63
|
+
const child_of = options.child_of ?? null;
|
|
64
|
+
const eventIsChildOf = options.event_is_child_of ?? ((event, ancestor) => this.eventIsChildOf(event, ancestor));
|
|
65
|
+
const waitForFutureMatch = options.wait_for_future_match;
|
|
66
|
+
if (past === false && future === false) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const event_key = EventHistory.normalizeEventPattern(event_pattern);
|
|
70
|
+
const cutoff_at = past === true ? null : monotonicDatetime(new Date(Date.now() - Math.max(0, Number(past)) * 1e3).toISOString());
|
|
71
|
+
const event_field_filters = Object.entries(options).filter(
|
|
72
|
+
([key, value]) => key !== "past" && key !== "future" && key !== "child_of" && key !== "event_is_child_of" && key !== "wait_for_future_match" && value !== void 0
|
|
73
|
+
);
|
|
74
|
+
const matches = (event) => (event_key === "*" || event.event_type === event_key) && (!child_of || eventIsChildOf(event, child_of)) && event_field_filters.every(([field_name, expected]) => event[field_name] === expected) && where(event);
|
|
75
|
+
if (past !== false) {
|
|
76
|
+
const history_values = Array.from(this._events.values());
|
|
77
|
+
for (let i = history_values.length - 1; i >= 0; i -= 1) {
|
|
78
|
+
const event = history_values[i];
|
|
79
|
+
if (cutoff_at !== null && event.event_created_at < cutoff_at) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (matches(event)) {
|
|
83
|
+
return event;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (future === false || !waitForFutureMatch) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return await waitForFutureMatch(event_key, matches, future);
|
|
91
|
+
}
|
|
92
|
+
trimEventHistory(options = {}) {
|
|
93
|
+
const max_history_size = options.max_history_size ?? this.max_history_size;
|
|
94
|
+
const max_history_drop = options.max_history_drop ?? this.max_history_drop;
|
|
95
|
+
if (max_history_size === null) {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
const is_event_complete = options.is_event_complete ?? ((event) => event.event_status === "completed");
|
|
99
|
+
const on_remove = options.on_remove;
|
|
100
|
+
if (max_history_size === 0) {
|
|
101
|
+
let removed_count2 = 0;
|
|
102
|
+
for (const [event_id, event] of Array.from(this._events.entries())) {
|
|
103
|
+
if (!is_event_complete(event)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
this._events.delete(event_id);
|
|
107
|
+
on_remove?.(event);
|
|
108
|
+
removed_count2 += 1;
|
|
109
|
+
}
|
|
110
|
+
return removed_count2;
|
|
111
|
+
}
|
|
112
|
+
if (!max_history_drop || this.size <= max_history_size) {
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
let remaining_overage = this.size - max_history_size;
|
|
116
|
+
let removed_count = 0;
|
|
117
|
+
const remove_event = (event_id, event) => {
|
|
118
|
+
this._events.delete(event_id);
|
|
119
|
+
on_remove?.(event);
|
|
120
|
+
removed_count += 1;
|
|
121
|
+
};
|
|
122
|
+
for (const [event_id, event] of Array.from(this._events.entries())) {
|
|
123
|
+
if (remaining_overage <= 0) {
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
if (!is_event_complete(event)) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
remove_event(event_id, event);
|
|
130
|
+
remaining_overage -= 1;
|
|
131
|
+
}
|
|
132
|
+
let dropped_uncompleted = 0;
|
|
133
|
+
for (const [event_id, event] of Array.from(this._events.entries())) {
|
|
134
|
+
if (remaining_overage <= 0) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
if (!is_event_complete(event)) {
|
|
138
|
+
dropped_uncompleted += 1;
|
|
139
|
+
}
|
|
140
|
+
remove_event(event_id, event);
|
|
141
|
+
remaining_overage -= 1;
|
|
142
|
+
}
|
|
143
|
+
if (dropped_uncompleted > 0 && !this._warned_about_dropping_uncompleted_events) {
|
|
144
|
+
this._warned_about_dropping_uncompleted_events = true;
|
|
145
|
+
const owner_label = options.owner_label ?? "EventBus";
|
|
146
|
+
console.error(
|
|
147
|
+
`[bubus] \u26A0\uFE0F Bus ${owner_label} has exceeded max_history_size=${max_history_size} and is dropping oldest history entries (even uncompleted events). Increase max_history_size or set max_history_drop=false to reject.`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return removed_count;
|
|
151
|
+
}
|
|
152
|
+
eventIsChildOf(event, ancestor) {
|
|
153
|
+
let current_parent_id = event.event_parent_id;
|
|
154
|
+
const visited = /* @__PURE__ */ new Set();
|
|
155
|
+
while (current_parent_id && !visited.has(current_parent_id)) {
|
|
156
|
+
if (current_parent_id === ancestor.event_id) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
visited.add(current_parent_id);
|
|
160
|
+
const parent = this._events.get(current_parent_id);
|
|
161
|
+
if (!parent) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
current_parent_id = parent.event_parent_id;
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
export {
|
|
170
|
+
EventHistory
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=event_history.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/event_history.ts"],
|
|
4
|
+
"sourcesContent": ["import { BaseEvent } from './base_event.js'\nimport type { EventPattern, FindWindow } from './types.js'\nimport { normalizeEventPattern } from './types.js'\nimport { monotonicDatetime } from './helpers.js'\n\nexport type EventHistoryFindOptions = {\n past?: FindWindow\n future?: FindWindow\n child_of?: BaseEvent | null\n event_is_child_of?: (event: BaseEvent, ancestor: BaseEvent) => boolean\n wait_for_future_match?: (\n event_pattern: string | '*',\n matches: (event: BaseEvent) => boolean,\n future: FindWindow\n ) => Promise<BaseEvent | null>\n} & Record<string, unknown>\n\nexport type EventHistoryTrimOptions<TEvent extends BaseEvent = BaseEvent> = {\n is_event_complete?: (event: TEvent) => boolean\n on_remove?: (event: TEvent) => void\n owner_label?: string\n max_history_size?: number | null\n max_history_drop?: boolean\n}\n\nexport class EventHistory<TEvent extends BaseEvent = BaseEvent> implements Iterable<[string, TEvent]> {\n max_history_size: number | null\n max_history_drop: boolean\n\n private _events: Map<string, TEvent>\n private _warned_about_dropping_uncompleted_events: boolean\n\n constructor(options: { max_history_size?: number | null; max_history_drop?: boolean } = {}) {\n this.max_history_size = options.max_history_size === undefined ? 100 : options.max_history_size\n this.max_history_drop = options.max_history_drop ?? false\n this._events = new Map()\n this._warned_about_dropping_uncompleted_events = false\n }\n\n get size(): number {\n return this._events.size\n }\n\n [Symbol.iterator](): Iterator<[string, TEvent]> {\n return this._events[Symbol.iterator]()\n }\n\n entries(): IterableIterator<[string, TEvent]> {\n return this._events.entries()\n }\n\n keys(): IterableIterator<string> {\n return this._events.keys()\n }\n\n values(): IterableIterator<TEvent> {\n return this._events.values()\n }\n\n clear(): void {\n this._events.clear()\n }\n\n get(event_id: string): TEvent | undefined {\n return this._events.get(event_id)\n }\n\n set(event_id: string, event: TEvent): this {\n this._events.set(event_id, event)\n return this\n }\n\n has(event_id: string): boolean {\n return this._events.has(event_id)\n }\n\n delete(event_id: string): boolean {\n return this._events.delete(event_id)\n }\n\n addEvent(event: TEvent): void {\n this._events.set(event.event_id, event)\n }\n\n getEvent(event_id: string): TEvent | undefined {\n return this._events.get(event_id)\n }\n\n removeEvent(event_id: string): boolean {\n return this._events.delete(event_id)\n }\n\n hasEvent(event_id: string): boolean {\n return this._events.has(event_id)\n }\n\n static normalizeEventPattern(event_pattern: EventPattern | '*'): string | '*' {\n return normalizeEventPattern(event_pattern)\n }\n\n find(event_pattern: '*', where?: (event: TEvent) => boolean, options?: EventHistoryFindOptions): Promise<TEvent | null>\n find<TMatch extends TEvent>(\n event_pattern: EventPattern<TMatch>,\n where?: (event: TMatch) => boolean,\n options?: EventHistoryFindOptions\n ): Promise<TMatch | null>\n async find(\n event_pattern: EventPattern<TEvent> | '*',\n where: (event: TEvent) => boolean = () => true,\n options: EventHistoryFindOptions = {}\n ): Promise<TEvent | null> {\n const past = options.past ?? true\n const future = options.future ?? false\n const child_of = options.child_of ?? null\n const eventIsChildOf = options.event_is_child_of ?? ((event: BaseEvent, ancestor: BaseEvent) => this.eventIsChildOf(event, ancestor))\n const waitForFutureMatch = options.wait_for_future_match\n if (past === false && future === false) {\n return null\n }\n\n const event_key = EventHistory.normalizeEventPattern(event_pattern)\n const cutoff_at = past === true ? null : monotonicDatetime(new Date(Date.now() - Math.max(0, Number(past)) * 1000).toISOString())\n\n const event_field_filters = Object.entries(options).filter(\n ([key, value]) =>\n key !== 'past' &&\n key !== 'future' &&\n key !== 'child_of' &&\n key !== 'event_is_child_of' &&\n key !== 'wait_for_future_match' &&\n value !== undefined\n )\n\n const matches = (event: BaseEvent): boolean =>\n (event_key === '*' || event.event_type === event_key) &&\n (!child_of || eventIsChildOf(event, child_of)) &&\n event_field_filters.every(([field_name, expected]) => (event as unknown as Record<string, unknown>)[field_name] === expected) &&\n where(event as TEvent)\n\n if (past !== false) {\n const history_values = Array.from(this._events.values())\n for (let i = history_values.length - 1; i >= 0; i -= 1) {\n const event = history_values[i]\n if (cutoff_at !== null && event.event_created_at < cutoff_at) {\n continue\n }\n if (matches(event)) {\n return event\n }\n }\n }\n\n if (future === false || !waitForFutureMatch) {\n return null\n }\n\n return (await waitForFutureMatch(event_key, matches, future)) as TEvent | null\n }\n\n trimEventHistory(options: EventHistoryTrimOptions<TEvent> = {}): number {\n const max_history_size = options.max_history_size ?? this.max_history_size\n const max_history_drop = options.max_history_drop ?? this.max_history_drop\n if (max_history_size === null) {\n return 0\n }\n\n const is_event_complete = options.is_event_complete ?? ((event: TEvent) => event.event_status === 'completed')\n const on_remove = options.on_remove\n\n if (max_history_size === 0) {\n let removed_count = 0\n for (const [event_id, event] of Array.from(this._events.entries())) {\n if (!is_event_complete(event)) {\n continue\n }\n this._events.delete(event_id)\n on_remove?.(event)\n removed_count += 1\n }\n return removed_count\n }\n\n if (!max_history_drop || this.size <= max_history_size) {\n return 0\n }\n\n let remaining_overage = this.size - max_history_size\n let removed_count = 0\n const remove_event = (event_id: string, event: TEvent): void => {\n this._events.delete(event_id)\n on_remove?.(event)\n removed_count += 1\n }\n\n for (const [event_id, event] of Array.from(this._events.entries())) {\n if (remaining_overage <= 0) {\n break\n }\n if (!is_event_complete(event)) {\n continue\n }\n remove_event(event_id, event)\n remaining_overage -= 1\n }\n\n let dropped_uncompleted = 0\n for (const [event_id, event] of Array.from(this._events.entries())) {\n if (remaining_overage <= 0) {\n break\n }\n if (!is_event_complete(event)) {\n dropped_uncompleted += 1\n }\n remove_event(event_id, event)\n remaining_overage -= 1\n }\n\n if (dropped_uncompleted > 0 && !this._warned_about_dropping_uncompleted_events) {\n this._warned_about_dropping_uncompleted_events = true\n const owner_label = options.owner_label ?? 'EventBus'\n console.error(\n `[bubus] \u26A0\uFE0F Bus ${owner_label} has exceeded max_history_size=${max_history_size} and is dropping oldest history entries (even uncompleted events). Increase max_history_size or set max_history_drop=false to reject.`\n )\n }\n\n return removed_count\n }\n\n private eventIsChildOf(event: BaseEvent, ancestor: BaseEvent): boolean {\n let current_parent_id = event.event_parent_id\n const visited = new Set<string>()\n\n while (current_parent_id && !visited.has(current_parent_id)) {\n if (current_parent_id === ancestor.event_id) {\n return true\n }\n visited.add(current_parent_id)\n const parent = this._events.get(current_parent_id)\n if (!parent) {\n return false\n }\n current_parent_id = parent.event_parent_id\n }\n\n return false\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["removed_count"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import { v7 as uuidv7 } from "uuid";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { BaseEvent } from "./base_event.js";
|
|
4
|
+
import { EventHandler, EventHandlerCancelledError, EventHandlerResultSchemaError, EventHandlerTimeoutError } from "./event_handler.js";
|
|
5
|
+
import { withResolvers } from "./lock_manager.js";
|
|
6
|
+
import { isZodSchema } from "./types.js";
|
|
7
|
+
import { _runWithAsyncContext } from "./async_context.js";
|
|
8
|
+
import { RetryTimeoutError } from "./retry.js";
|
|
9
|
+
import { _runWithAbortMonitor, _runWithSlowMonitor, _runWithTimeout } from "./timing.js";
|
|
10
|
+
import { monotonicDatetime } from "./helpers.js";
|
|
11
|
+
const EventResultJSONSchema = z.object({
|
|
12
|
+
id: z.string(),
|
|
13
|
+
status: z.enum(["pending", "started", "completed", "error"]),
|
|
14
|
+
event_id: z.string(),
|
|
15
|
+
handler_id: z.string(),
|
|
16
|
+
handler_name: z.string(),
|
|
17
|
+
handler_file_path: z.string().nullable().optional(),
|
|
18
|
+
handler_timeout: z.number().nullable().optional(),
|
|
19
|
+
handler_slow_timeout: z.number().nullable().optional(),
|
|
20
|
+
handler_registered_at: z.string().datetime().optional(),
|
|
21
|
+
handler_event_pattern: z.union([z.string(), z.literal("*")]).optional(),
|
|
22
|
+
eventbus_name: z.string(),
|
|
23
|
+
eventbus_id: z.string().uuid(),
|
|
24
|
+
started_at: z.string().datetime().nullable().optional(),
|
|
25
|
+
completed_at: z.string().datetime().nullable().optional(),
|
|
26
|
+
result: z.unknown().optional(),
|
|
27
|
+
error: z.unknown().optional(),
|
|
28
|
+
event_children: z.array(z.string())
|
|
29
|
+
}).strict();
|
|
30
|
+
class EventResult {
|
|
31
|
+
id;
|
|
32
|
+
// unique uuidv7 identifier for the event result
|
|
33
|
+
status;
|
|
34
|
+
// 'pending', 'started', 'completed', or 'error'
|
|
35
|
+
event;
|
|
36
|
+
// the Event that the handler is processing
|
|
37
|
+
handler;
|
|
38
|
+
// the EventHandler object that going to process the event
|
|
39
|
+
started_at;
|
|
40
|
+
completed_at;
|
|
41
|
+
result;
|
|
42
|
+
// parsed return value from the event handler
|
|
43
|
+
error;
|
|
44
|
+
// error object thrown by the event handler, or null if the handler completed successfully
|
|
45
|
+
event_children;
|
|
46
|
+
// list of emitted child events
|
|
47
|
+
// Abort signal: created when handler starts, rejected by _signalAbort() to
|
|
48
|
+
// interrupt runHandler's await via Promise.race.
|
|
49
|
+
_abort;
|
|
50
|
+
// Handler lock: tracks ownership of the handler concurrency lock
|
|
51
|
+
// during handler execution. Set by runHandler(), used by
|
|
52
|
+
// _processEventImmediately for yield-and-reacquire during queue-jumps.
|
|
53
|
+
_lock;
|
|
54
|
+
// Runloop pause releases keyed by bus for queue-jump; released when handler exits.
|
|
55
|
+
_queue_jump_pause_releases;
|
|
56
|
+
constructor(params) {
|
|
57
|
+
this.id = uuidv7();
|
|
58
|
+
this.status = "pending";
|
|
59
|
+
this.event = params.event;
|
|
60
|
+
this.handler = params.handler;
|
|
61
|
+
this.started_at = null;
|
|
62
|
+
this.completed_at = null;
|
|
63
|
+
this.result = void 0;
|
|
64
|
+
this.error = void 0;
|
|
65
|
+
this.event_children = [];
|
|
66
|
+
this._abort = null;
|
|
67
|
+
this._lock = null;
|
|
68
|
+
this._queue_jump_pause_releases = null;
|
|
69
|
+
}
|
|
70
|
+
toString() {
|
|
71
|
+
return `${this.result ?? "null"} (${this.status})`;
|
|
72
|
+
}
|
|
73
|
+
get event_id() {
|
|
74
|
+
return this.event.event_id;
|
|
75
|
+
}
|
|
76
|
+
get bus() {
|
|
77
|
+
return this.event.bus;
|
|
78
|
+
}
|
|
79
|
+
get handler_id() {
|
|
80
|
+
return this.handler.id;
|
|
81
|
+
}
|
|
82
|
+
get handler_name() {
|
|
83
|
+
return this.handler.handler_name;
|
|
84
|
+
}
|
|
85
|
+
get handler_file_path() {
|
|
86
|
+
return this.handler.handler_file_path;
|
|
87
|
+
}
|
|
88
|
+
get eventbus_name() {
|
|
89
|
+
return this.handler.eventbus_name;
|
|
90
|
+
}
|
|
91
|
+
get eventbus_id() {
|
|
92
|
+
return this.handler.eventbus_id;
|
|
93
|
+
}
|
|
94
|
+
get eventbus_label() {
|
|
95
|
+
return `${this.handler.eventbus_name}#${this.handler.eventbus_id.slice(-4)}`;
|
|
96
|
+
}
|
|
97
|
+
getHookBus() {
|
|
98
|
+
const root_bus = this.event.bus;
|
|
99
|
+
if (!root_bus) {
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
return root_bus.all_instances.findBusById(this.eventbus_id) ?? root_bus;
|
|
103
|
+
}
|
|
104
|
+
async _notifyStatusHook(status) {
|
|
105
|
+
const hook_bus = this.getHookBus();
|
|
106
|
+
if (!hook_bus) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const event_for_hook = hook_bus._getEventProxyScopedToThisBus(this.event._event_original ?? this.event, this);
|
|
110
|
+
await hook_bus.onEventResultChange(event_for_hook, this, status);
|
|
111
|
+
}
|
|
112
|
+
// shortcut for the result value so users can do event_result.value instead of event_result.result
|
|
113
|
+
get value() {
|
|
114
|
+
return this.result;
|
|
115
|
+
}
|
|
116
|
+
// Per-result schema reference derives from the parent event schema.
|
|
117
|
+
// It is intentionally not serialized with each EventResult to avoid duplication.
|
|
118
|
+
get result_type() {
|
|
119
|
+
const original_event = this.event._event_original ?? this.event;
|
|
120
|
+
return original_event.event_result_type;
|
|
121
|
+
}
|
|
122
|
+
// Link a child event emitted by this handler run to the parent event/result.
|
|
123
|
+
_linkEmittedChildEvent(child_event) {
|
|
124
|
+
const original_child = child_event._event_original ?? child_event;
|
|
125
|
+
const parent_event = this.event._event_original ?? this.event;
|
|
126
|
+
if (original_child.event_id === parent_event.event_id) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (!original_child.event_parent_id) {
|
|
130
|
+
original_child.event_parent_id = parent_event.event_id;
|
|
131
|
+
}
|
|
132
|
+
if (!original_child.event_emitted_by_handler_id) {
|
|
133
|
+
original_child.event_emitted_by_handler_id = this.handler_id;
|
|
134
|
+
}
|
|
135
|
+
if (!this.event_children.some((child) => child.event_id === original_child.event_id)) {
|
|
136
|
+
this.event_children.push(original_child);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Get the raw return value from the handler, even if it threw an error / failed validation
|
|
140
|
+
get raw_value() {
|
|
141
|
+
if (this.error && this.error.raw_value !== void 0) {
|
|
142
|
+
return this.error.raw_value;
|
|
143
|
+
}
|
|
144
|
+
return this.result;
|
|
145
|
+
}
|
|
146
|
+
// Resolve handler timeout in seconds using precedence: handler -> event -> bus defaults.
|
|
147
|
+
get handler_timeout() {
|
|
148
|
+
const original = this.event._event_original ?? this.event;
|
|
149
|
+
const resolved_event_timeout = original.event_timeout ?? this.bus.event_timeout;
|
|
150
|
+
let resolved_handler_timeout;
|
|
151
|
+
if (this.handler.handler_timeout !== void 0) {
|
|
152
|
+
resolved_handler_timeout = this.handler.handler_timeout;
|
|
153
|
+
} else if (original.event_handler_timeout !== void 0) {
|
|
154
|
+
resolved_handler_timeout = original.event_handler_timeout;
|
|
155
|
+
} else {
|
|
156
|
+
resolved_handler_timeout = this.bus.event_timeout;
|
|
157
|
+
}
|
|
158
|
+
if (resolved_handler_timeout === null && resolved_event_timeout === null) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
if (resolved_handler_timeout === null) {
|
|
162
|
+
return resolved_event_timeout;
|
|
163
|
+
}
|
|
164
|
+
if (resolved_event_timeout === null) {
|
|
165
|
+
return resolved_handler_timeout;
|
|
166
|
+
}
|
|
167
|
+
return Math.min(resolved_handler_timeout, resolved_event_timeout);
|
|
168
|
+
}
|
|
169
|
+
// Resolve slow handler warning threshold in seconds using precedence: handler -> event -> bus defaults.
|
|
170
|
+
get handler_slow_timeout() {
|
|
171
|
+
const original = this.event._event_original ?? this.event;
|
|
172
|
+
if (this.handler.handler_slow_timeout !== void 0) {
|
|
173
|
+
return this.handler.handler_slow_timeout;
|
|
174
|
+
}
|
|
175
|
+
if (original.event_handler_slow_timeout !== void 0) {
|
|
176
|
+
return original.event_handler_slow_timeout;
|
|
177
|
+
}
|
|
178
|
+
const event_slow_timeout = original.event_slow_timeout;
|
|
179
|
+
if (event_slow_timeout !== void 0) {
|
|
180
|
+
return event_slow_timeout;
|
|
181
|
+
}
|
|
182
|
+
if (this.bus?.event_handler_slow_timeout !== void 0) {
|
|
183
|
+
return this.bus.event_handler_slow_timeout;
|
|
184
|
+
}
|
|
185
|
+
return this.bus?.event_slow_timeout ?? null;
|
|
186
|
+
}
|
|
187
|
+
// Create a slow-handler warning timer that logs if the handler runs too long.
|
|
188
|
+
_createSlowHandlerWarningTimer(effective_timeout) {
|
|
189
|
+
const handler_warn_timeout = this.handler_slow_timeout;
|
|
190
|
+
const warn_ms = handler_warn_timeout === null ? null : handler_warn_timeout * 1e3;
|
|
191
|
+
const should_warn = warn_ms !== null && (effective_timeout === null || effective_timeout * 1e3 > warn_ms);
|
|
192
|
+
if (!should_warn || warn_ms === null) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
const event = this.event._event_original ?? this.event;
|
|
196
|
+
const bus_name = this.handler.eventbus_name;
|
|
197
|
+
const started_at_ms = performance.now();
|
|
198
|
+
return setTimeout(() => {
|
|
199
|
+
if (this.status !== "started") {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const elapsed_ms = performance.now() - started_at_ms;
|
|
203
|
+
const elapsed_seconds = (elapsed_ms / 1e3).toFixed(1);
|
|
204
|
+
console.warn(
|
|
205
|
+
`[bubus] Slow event handler: ${bus_name}.on(${event.toString()}, ${this.handler.toString()}) still running after ${elapsed_seconds}s`
|
|
206
|
+
);
|
|
207
|
+
}, warn_ms);
|
|
208
|
+
}
|
|
209
|
+
_ensureQueueJumpPause(bus) {
|
|
210
|
+
if (!this._queue_jump_pause_releases) {
|
|
211
|
+
this._queue_jump_pause_releases = /* @__PURE__ */ new Map();
|
|
212
|
+
}
|
|
213
|
+
if (this._queue_jump_pause_releases.has(bus)) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this._queue_jump_pause_releases.set(bus, bus.locks._requestRunloopPause());
|
|
217
|
+
}
|
|
218
|
+
_releaseQueueJumpPauses() {
|
|
219
|
+
if (!this._queue_jump_pause_releases) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
for (const release of this._queue_jump_pause_releases.values()) {
|
|
223
|
+
release();
|
|
224
|
+
}
|
|
225
|
+
this._queue_jump_pause_releases.clear();
|
|
226
|
+
}
|
|
227
|
+
update(params) {
|
|
228
|
+
const has_status = "status" in params;
|
|
229
|
+
const has_result = "result" in params;
|
|
230
|
+
const has_error = "error" in params;
|
|
231
|
+
if (has_result) {
|
|
232
|
+
const raw_result = params.result;
|
|
233
|
+
this.status = "completed";
|
|
234
|
+
if (this.event.event_result_type && raw_result !== void 0 && !(raw_result instanceof BaseEvent) && isZodSchema(this.event.event_result_type)) {
|
|
235
|
+
const parsed = this.event.event_result_type.safeParse(raw_result);
|
|
236
|
+
if (parsed.success) {
|
|
237
|
+
this.result = parsed.data;
|
|
238
|
+
} else {
|
|
239
|
+
const error = new EventHandlerResultSchemaError(
|
|
240
|
+
`Event handler return value ${JSON.stringify(raw_result).slice(0, 20)}... did not match event_result_type: ${parsed.error.message}`,
|
|
241
|
+
{ event_result: this, cause: parsed.error, raw_value: raw_result }
|
|
242
|
+
);
|
|
243
|
+
this.error = error;
|
|
244
|
+
this.result = void 0;
|
|
245
|
+
this.status = "error";
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
this.result = raw_result;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (has_error) {
|
|
252
|
+
this.error = params.error;
|
|
253
|
+
this.status = "error";
|
|
254
|
+
}
|
|
255
|
+
if (has_status && params.status !== void 0) {
|
|
256
|
+
this.status = params.status;
|
|
257
|
+
}
|
|
258
|
+
if (this.status !== "pending" && this.started_at === null) {
|
|
259
|
+
this.started_at = monotonicDatetime();
|
|
260
|
+
}
|
|
261
|
+
if ((this.status === "completed" || this.status === "error") && this.completed_at === null) {
|
|
262
|
+
this.completed_at = monotonicDatetime();
|
|
263
|
+
}
|
|
264
|
+
return this;
|
|
265
|
+
}
|
|
266
|
+
_createHandlerTimeoutError(event) {
|
|
267
|
+
return new EventHandlerTimeoutError(
|
|
268
|
+
`${this.bus.toString()}.on(${event.toString()}, ${this.handler.toString()}) timed out after ${this.handler_timeout}s`,
|
|
269
|
+
{
|
|
270
|
+
event_result: this,
|
|
271
|
+
timeout_seconds: this.handler_timeout
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
_handleHandlerError(event, error) {
|
|
276
|
+
const normalized_error = error instanceof RetryTimeoutError ? new EventHandlerTimeoutError(error.message, { event_result: this, timeout_seconds: error.timeout_seconds, cause: error }) : error;
|
|
277
|
+
if (normalized_error instanceof EventHandlerTimeoutError) {
|
|
278
|
+
this._markError(normalized_error, false);
|
|
279
|
+
event._cancelPendingChildProcessing(normalized_error);
|
|
280
|
+
} else {
|
|
281
|
+
this._markError(normalized_error, false);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
_onHandlerExit(slow_handler_warning_timer) {
|
|
285
|
+
this._abort = null;
|
|
286
|
+
this._lock = null;
|
|
287
|
+
this._releaseQueueJumpPauses();
|
|
288
|
+
if (slow_handler_warning_timer) {
|
|
289
|
+
clearTimeout(slow_handler_warning_timer);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Run one handler invocation with timeout/slow-monitor/error handling.
|
|
293
|
+
// Handler lock acquisition is owned by BaseEvent._runHandlers(...).
|
|
294
|
+
async runHandler(handler_lock) {
|
|
295
|
+
if (this.status === "error" && this.error instanceof EventHandlerCancelledError) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const event = this.event._event_original ?? this.event;
|
|
299
|
+
const handler_event = this.bus._getEventProxyScopedToThisBus(event, this);
|
|
300
|
+
if (this._lock) {
|
|
301
|
+
this._lock.exitHandlerRun();
|
|
302
|
+
}
|
|
303
|
+
let slow_handler_warning_timer = null;
|
|
304
|
+
if (this.status === "error" || this.status === "completed") {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
this._lock = handler_lock;
|
|
308
|
+
await this.bus.locks._runWithHandlerDispatchContext(this, async () => {
|
|
309
|
+
await _runWithAsyncContext(event._getDispatchContext() ?? null, async () => {
|
|
310
|
+
try {
|
|
311
|
+
const should_notify_started = this.status === "pending";
|
|
312
|
+
const abort_signal = this._markStarted(false);
|
|
313
|
+
if (should_notify_started) {
|
|
314
|
+
await this._notifyStatusHook("started");
|
|
315
|
+
}
|
|
316
|
+
slow_handler_warning_timer = this._createSlowHandlerWarningTimer(this.handler_timeout);
|
|
317
|
+
const handler_result = await _runWithTimeout(
|
|
318
|
+
this.handler_timeout,
|
|
319
|
+
() => this._createHandlerTimeoutError(event),
|
|
320
|
+
() => _runWithSlowMonitor(
|
|
321
|
+
slow_handler_warning_timer,
|
|
322
|
+
() => _runWithAbortMonitor(() => this.handler._handler_async(handler_event), abort_signal)
|
|
323
|
+
)
|
|
324
|
+
);
|
|
325
|
+
this._markCompleted(handler_result, false);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
this._handleHandlerError(event, error);
|
|
328
|
+
} finally {
|
|
329
|
+
if (this.status === "completed" || this.status === "error") {
|
|
330
|
+
await this._notifyStatusHook("completed");
|
|
331
|
+
}
|
|
332
|
+
this._onHandlerExit(slow_handler_warning_timer);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
// Reject the abort promise, causing runHandler's Promise.race to
|
|
338
|
+
// throw immediately — even if the handler has no timeout.
|
|
339
|
+
_signalAbort(error) {
|
|
340
|
+
if (this._abort) {
|
|
341
|
+
this._abort.reject(error);
|
|
342
|
+
this._abort = null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Mark started and return the abort promise for Promise.race.
|
|
346
|
+
_markStarted(notify_hook = true) {
|
|
347
|
+
if (!this._abort) {
|
|
348
|
+
this._abort = withResolvers();
|
|
349
|
+
}
|
|
350
|
+
if (this.status === "pending") {
|
|
351
|
+
this.update({ status: "started" });
|
|
352
|
+
if (notify_hook) {
|
|
353
|
+
void this._notifyStatusHook("started");
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return this._abort.promise;
|
|
357
|
+
}
|
|
358
|
+
_markCompleted(result, notify_hook = true) {
|
|
359
|
+
if (this.status === "completed" || this.status === "error") return;
|
|
360
|
+
this.update({ result });
|
|
361
|
+
if (notify_hook) {
|
|
362
|
+
void this._notifyStatusHook("completed");
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
_markError(error, notify_hook = true) {
|
|
366
|
+
if (this.status === "completed" || this.status === "error") return;
|
|
367
|
+
this.update({ error });
|
|
368
|
+
if (notify_hook) {
|
|
369
|
+
void this._notifyStatusHook("completed");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
toJSON() {
|
|
373
|
+
return {
|
|
374
|
+
id: this.id,
|
|
375
|
+
status: this.status,
|
|
376
|
+
event_id: this.event.event_id,
|
|
377
|
+
handler_id: this.handler_id,
|
|
378
|
+
handler_name: this.handler_name,
|
|
379
|
+
handler_file_path: this.handler_file_path,
|
|
380
|
+
handler_timeout: this.handler.handler_timeout,
|
|
381
|
+
handler_slow_timeout: this.handler.handler_slow_timeout,
|
|
382
|
+
handler_registered_at: this.handler.handler_registered_at,
|
|
383
|
+
handler_event_pattern: this.handler.event_pattern,
|
|
384
|
+
eventbus_name: this.eventbus_name,
|
|
385
|
+
eventbus_id: this.eventbus_id,
|
|
386
|
+
started_at: this.started_at,
|
|
387
|
+
completed_at: this.completed_at,
|
|
388
|
+
result: this.result,
|
|
389
|
+
error: this.error,
|
|
390
|
+
event_children: this.event_children.map((child) => child.event_id)
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
static fromJSON(event, data) {
|
|
394
|
+
const record = EventResultJSONSchema.parse(data);
|
|
395
|
+
const handler_record = {
|
|
396
|
+
id: record.handler_id,
|
|
397
|
+
eventbus_name: record.eventbus_name,
|
|
398
|
+
eventbus_id: record.eventbus_id,
|
|
399
|
+
event_pattern: record.handler_event_pattern ?? event.event_type,
|
|
400
|
+
handler_name: record.handler_name,
|
|
401
|
+
handler_file_path: record.handler_file_path ?? null,
|
|
402
|
+
handler_timeout: record.handler_timeout,
|
|
403
|
+
handler_slow_timeout: record.handler_slow_timeout,
|
|
404
|
+
handler_registered_at: record.handler_registered_at ?? event.event_created_at
|
|
405
|
+
};
|
|
406
|
+
const handler_stub = EventHandler.fromJSON(handler_record, (() => void 0));
|
|
407
|
+
const result = new EventResult({ event, handler: handler_stub });
|
|
408
|
+
result.id = record.id;
|
|
409
|
+
result.status = record.status;
|
|
410
|
+
result.started_at = record.started_at === null || record.started_at === void 0 ? null : monotonicDatetime(record.started_at);
|
|
411
|
+
result.completed_at = record.completed_at === null || record.completed_at === void 0 ? null : monotonicDatetime(record.completed_at);
|
|
412
|
+
if ("result" in record) {
|
|
413
|
+
result.result = record.result;
|
|
414
|
+
}
|
|
415
|
+
if ("error" in record) {
|
|
416
|
+
result.error = record.error;
|
|
417
|
+
}
|
|
418
|
+
result.event_children = [];
|
|
419
|
+
return result;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
export {
|
|
423
|
+
EventResult,
|
|
424
|
+
EventResultJSONSchema
|
|
425
|
+
};
|
|
426
|
+
//# sourceMappingURL=event_result.js.map
|