@dxos/async 0.7.5-main.9d26e3a → 0.7.5-main.b19bfc8
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/dist/lib/browser/index.mjs +481 -330
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +475 -327
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +481 -330
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/events.d.ts +13 -2
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +6 -5
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/persistent-lifecycle.d.ts +45 -0
- package/dist/types/src/persistent-lifecycle.d.ts.map +1 -0
- package/dist/types/src/persistent-lifecycle.test.d.ts +2 -0
- package/dist/types/src/persistent-lifecycle.test.d.ts.map +1 -0
- package/dist/types/src/task-scheduling.d.ts +1 -0
- package/dist/types/src/task-scheduling.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/src/events.test.ts +15 -0
- package/src/events.ts +49 -9
- package/src/index.ts +6 -5
- package/src/persistent-lifecycle.test.ts +77 -0
- package/src/persistent-lifecycle.ts +128 -0
- package/src/task-scheduling.ts +4 -0
package/dist/lib/node/index.cjs
CHANGED
|
@@ -37,6 +37,7 @@ __export(node_exports, {
|
|
|
37
37
|
MutexGuard: () => MutexGuard,
|
|
38
38
|
Observable: () => import_zen_observable.default,
|
|
39
39
|
ObservableProvider: () => ObservableProvider,
|
|
40
|
+
PersistentLifecycle: () => PersistentLifecycle,
|
|
40
41
|
PushStream: () => import_zen_push.default,
|
|
41
42
|
TestStream: () => TestStream,
|
|
42
43
|
TimeoutError: () => TimeoutError,
|
|
@@ -80,15 +81,18 @@ module.exports = __toCommonJS(node_exports);
|
|
|
80
81
|
var import_context = require("@dxos/context");
|
|
81
82
|
var import_context2 = require("@dxos/context");
|
|
82
83
|
var import_invariant = require("@dxos/invariant");
|
|
84
|
+
var import_util = require("@dxos/util");
|
|
85
|
+
var import_debug = require("@dxos/debug");
|
|
83
86
|
var import_zen_observable = __toESM(require("zen-observable"));
|
|
84
87
|
var import_zen_push = __toESM(require("zen-push"));
|
|
85
|
-
var import_util = require("@dxos/util");
|
|
86
88
|
var import_util2 = require("@dxos/util");
|
|
87
|
-
var import_debug = require("@dxos/debug");
|
|
88
89
|
var import_context3 = require("@dxos/context");
|
|
89
90
|
var import_debug2 = require("@dxos/debug");
|
|
90
|
-
var import_debug3 = require("@dxos/debug");
|
|
91
91
|
var import_log = require("@dxos/log");
|
|
92
|
+
var import_context4 = require("@dxos/context");
|
|
93
|
+
var import_debug3 = require("@dxos/debug");
|
|
94
|
+
var import_debug4 = require("@dxos/debug");
|
|
95
|
+
var import_log2 = require("@dxos/log");
|
|
92
96
|
var import_node_stream = require("node:stream");
|
|
93
97
|
var createPromiseFromCallback = (run) => new Promise((resolve, reject) => {
|
|
94
98
|
run((error, value) => {
|
|
@@ -214,6 +218,7 @@ var EventSubscriptions = class {
|
|
|
214
218
|
this._listeners.length = 0;
|
|
215
219
|
}
|
|
216
220
|
};
|
|
221
|
+
var DO_NOT_ERROR_ON_ASYNC_CALLBACK = true;
|
|
217
222
|
var Event = class _Event {
|
|
218
223
|
constructor() {
|
|
219
224
|
this._listeners = /* @__PURE__ */ new Set();
|
|
@@ -242,7 +247,23 @@ var Event = class _Event {
|
|
|
242
247
|
*/
|
|
243
248
|
emit(data) {
|
|
244
249
|
for (const listener of this._listeners) {
|
|
245
|
-
|
|
250
|
+
listener.trigger(data);
|
|
251
|
+
if (listener.once) {
|
|
252
|
+
this._listeners.delete(listener);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Emit an event and wait for async listeners to complete.
|
|
258
|
+
* In most cases should only be called by the class or entity containing the event.
|
|
259
|
+
* All listeners are called in order of subscription with persistent ones first.
|
|
260
|
+
* Listeners are called sequentially.
|
|
261
|
+
*
|
|
262
|
+
* @param data param that will be passed to all listeners.
|
|
263
|
+
*/
|
|
264
|
+
async emitAsync(data) {
|
|
265
|
+
for (const listener of this._listeners) {
|
|
266
|
+
await listener.triggerAsync(data);
|
|
246
267
|
if (listener.once) {
|
|
247
268
|
this._listeners.delete(listener);
|
|
248
269
|
}
|
|
@@ -255,7 +276,7 @@ var Event = class _Event {
|
|
|
255
276
|
] : [
|
|
256
277
|
new import_context2.Context(void 0, {
|
|
257
278
|
F: __dxlog_file,
|
|
258
|
-
L:
|
|
279
|
+
L: 148
|
|
259
280
|
}),
|
|
260
281
|
_ctx
|
|
261
282
|
];
|
|
@@ -288,7 +309,7 @@ var Event = class _Event {
|
|
|
288
309
|
] : [
|
|
289
310
|
new import_context2.Context(void 0, {
|
|
290
311
|
F: __dxlog_file,
|
|
291
|
-
L:
|
|
312
|
+
L: 185
|
|
292
313
|
}),
|
|
293
314
|
_ctx
|
|
294
315
|
];
|
|
@@ -472,7 +493,21 @@ var EventListener = class {
|
|
|
472
493
|
derefCallback() {
|
|
473
494
|
return this.weak ? this.callback.deref() : this.callback;
|
|
474
495
|
}
|
|
475
|
-
|
|
496
|
+
trigger(data) {
|
|
497
|
+
let result;
|
|
498
|
+
try {
|
|
499
|
+
const callback = this.derefCallback();
|
|
500
|
+
result = callback?.(data);
|
|
501
|
+
} catch (err) {
|
|
502
|
+
this.ctx.raise(err);
|
|
503
|
+
}
|
|
504
|
+
if (!DO_NOT_ERROR_ON_ASYNC_CALLBACK) {
|
|
505
|
+
if (result instanceof Promise) {
|
|
506
|
+
throw new TypeError("Event has async callbacks, use emitAsync instead");
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
async triggerAsync(data) {
|
|
476
511
|
try {
|
|
477
512
|
const callback = this.derefCallback();
|
|
478
513
|
await callback?.(data);
|
|
@@ -547,6 +582,94 @@ var latch = ({ count = 1, timeout } = {}) => {
|
|
|
547
582
|
(err) => doReject(err)
|
|
548
583
|
];
|
|
549
584
|
};
|
|
585
|
+
var Mutex = class {
|
|
586
|
+
constructor() {
|
|
587
|
+
this._queue = Promise.resolve();
|
|
588
|
+
this._queueLength = 0;
|
|
589
|
+
this._tag = null;
|
|
590
|
+
}
|
|
591
|
+
get tag() {
|
|
592
|
+
return this._tag;
|
|
593
|
+
}
|
|
594
|
+
isLocked() {
|
|
595
|
+
return this._queueLength > 0;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Acquires the lock.
|
|
599
|
+
* Caller is responsible for releasing the lock using the returned callback.
|
|
600
|
+
* NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
|
|
601
|
+
* @returns Release callback
|
|
602
|
+
*/
|
|
603
|
+
async acquire(tag) {
|
|
604
|
+
const prev = this._queue;
|
|
605
|
+
let guard;
|
|
606
|
+
this._queueLength++;
|
|
607
|
+
this._queue = new Promise((resolve) => {
|
|
608
|
+
guard = new MutexGuard(() => {
|
|
609
|
+
this._queueLength--;
|
|
610
|
+
this._tag = null;
|
|
611
|
+
resolve();
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
await prev;
|
|
615
|
+
if (tag !== void 0) {
|
|
616
|
+
this._tag = tag;
|
|
617
|
+
}
|
|
618
|
+
return guard;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Waits for all previous executions to complete and then executes a given function.
|
|
622
|
+
* Only a single function can be executed at a time.
|
|
623
|
+
* Function are executed in the same order as `executeSynchronized` is called.
|
|
624
|
+
* WARNING: Calling `executeSynchronized` inside of `executeSynchronized` on the same lock instance is a deadlock.
|
|
625
|
+
*/
|
|
626
|
+
async executeSynchronized(fun) {
|
|
627
|
+
const guard = await this.acquire();
|
|
628
|
+
try {
|
|
629
|
+
return await fun();
|
|
630
|
+
} finally {
|
|
631
|
+
guard.release();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
var MutexGuard = class {
|
|
636
|
+
constructor(_release) {
|
|
637
|
+
this._release = _release;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Releases the lock.
|
|
641
|
+
*/
|
|
642
|
+
release() {
|
|
643
|
+
this._release();
|
|
644
|
+
}
|
|
645
|
+
[Symbol.dispose]() {
|
|
646
|
+
this.release();
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
var classMutexSymbol = Symbol("class-mutex");
|
|
650
|
+
var FORCE_DISABLE_WARNING = false;
|
|
651
|
+
var enableWarning = !FORCE_DISABLE_WARNING && globalThis.mochaExecutor;
|
|
652
|
+
var synchronized = (target, propertyName, descriptor) => {
|
|
653
|
+
const method = descriptor.value;
|
|
654
|
+
descriptor.value = async function synchronizedMethod(...args) {
|
|
655
|
+
const mutex = this[classMutexSymbol] ??= new Mutex();
|
|
656
|
+
const tag = `${target.constructor.name}.${propertyName}`;
|
|
657
|
+
let guard;
|
|
658
|
+
if (!enableWarning) {
|
|
659
|
+
guard = await mutex.acquire(tag);
|
|
660
|
+
} else {
|
|
661
|
+
guard = await (0, import_debug.warnAfterTimeout)(1e4, `lock on ${tag} (taken by ${mutex.tag})`, () => mutex.acquire(tag));
|
|
662
|
+
}
|
|
663
|
+
try {
|
|
664
|
+
return await method.apply(this, args);
|
|
665
|
+
} finally {
|
|
666
|
+
guard.release();
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
Object.defineProperty(descriptor.value, "name", {
|
|
670
|
+
value: propertyName + "$synchronized"
|
|
671
|
+
});
|
|
672
|
+
};
|
|
550
673
|
var trigger = (timeout) => {
|
|
551
674
|
let callback;
|
|
552
675
|
const promise = new Promise((resolve, reject) => {
|
|
@@ -740,7 +863,7 @@ var EMPTY_OBSERVABLE = MulticastObservable.of(null);
|
|
|
740
863
|
var ObservableProvider = class {
|
|
741
864
|
constructor() {
|
|
742
865
|
this._handlers = /* @__PURE__ */ new Set();
|
|
743
|
-
this._proxy = (0,
|
|
866
|
+
this._proxy = (0, import_util2.createSetDispatch)({
|
|
744
867
|
handlers: this._handlers
|
|
745
868
|
});
|
|
746
869
|
}
|
|
@@ -781,94 +904,319 @@ var CancellableObservableProvider = class extends ObservableProvider {
|
|
|
781
904
|
this.callback.onCancelled?.();
|
|
782
905
|
}
|
|
783
906
|
};
|
|
784
|
-
var
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
907
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/async/src/track-leaks.ts";
|
|
908
|
+
var enabled = typeof process !== "undefined" && !!process.env.DX_TRACK_LEAKS;
|
|
909
|
+
var openResources = /* @__PURE__ */ new Set();
|
|
910
|
+
var handleSymbol = Symbol("checkLeaksHandle");
|
|
911
|
+
var trackResource = (resourceProvider) => {
|
|
912
|
+
if (!enabled) {
|
|
913
|
+
return () => {
|
|
914
|
+
};
|
|
789
915
|
}
|
|
790
|
-
|
|
791
|
-
|
|
916
|
+
const resource = resourceProvider();
|
|
917
|
+
openResources.add(resource);
|
|
918
|
+
return () => {
|
|
919
|
+
openResources.delete(resource);
|
|
920
|
+
};
|
|
921
|
+
};
|
|
922
|
+
var trackLeaks = (open, close) => (target) => {
|
|
923
|
+
if (!enabled) {
|
|
924
|
+
return;
|
|
792
925
|
}
|
|
793
|
-
|
|
794
|
-
|
|
926
|
+
const openMethod = target.prototype[open];
|
|
927
|
+
const closeMethod = target.prototype[close];
|
|
928
|
+
if (!openMethod || !closeMethod) {
|
|
929
|
+
throw new Error(`Cannot find ${open} or ${close} method in ${target.name}`);
|
|
930
|
+
}
|
|
931
|
+
{
|
|
932
|
+
target.prototype[open] = async function(...args) {
|
|
933
|
+
this[handleSymbol] = trackResource(() => ({
|
|
934
|
+
name: target.name,
|
|
935
|
+
openStack: new import_debug4.StackTrace()
|
|
936
|
+
}));
|
|
937
|
+
return openMethod.apply(this, args);
|
|
938
|
+
};
|
|
939
|
+
Object.defineProperty(target.prototype[open], "name", {
|
|
940
|
+
value: open + "$checkLeaks"
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
{
|
|
944
|
+
target.prototype[close] = async function(...args) {
|
|
945
|
+
this[handleSymbol]?.();
|
|
946
|
+
return closeMethod.apply(this, args);
|
|
947
|
+
};
|
|
948
|
+
Object.defineProperty(target.prototype[close], "name", {
|
|
949
|
+
value: close + "$checkLeaks"
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
var dumpLeaks = () => {
|
|
954
|
+
if (!enabled) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
import_log2.log.info(`Leaked resources ${openResources.size}:`, void 0, {
|
|
958
|
+
F: __dxlog_file3,
|
|
959
|
+
L: 82,
|
|
960
|
+
S: void 0,
|
|
961
|
+
C: (f, a) => f(...a)
|
|
962
|
+
});
|
|
963
|
+
for (const resource of openResources) {
|
|
964
|
+
import_log2.log.info(`- ${resource.name} at`, void 0, {
|
|
965
|
+
F: __dxlog_file3,
|
|
966
|
+
L: 84,
|
|
967
|
+
S: void 0,
|
|
968
|
+
C: (f, a) => f(...a)
|
|
969
|
+
});
|
|
970
|
+
import_log2.log.info(resource.openStack.getStack(1), void 0, {
|
|
971
|
+
F: __dxlog_file3,
|
|
972
|
+
L: 85,
|
|
973
|
+
S: void 0,
|
|
974
|
+
C: (f, a) => f(...a)
|
|
975
|
+
});
|
|
976
|
+
import_log2.log.info("\n", void 0, {
|
|
977
|
+
F: __dxlog_file3,
|
|
978
|
+
L: 86,
|
|
979
|
+
S: void 0,
|
|
980
|
+
C: (f, a) => f(...a)
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
if (enabled) {
|
|
985
|
+
global.dxDumpLeaks = dumpLeaks;
|
|
986
|
+
}
|
|
987
|
+
var DeferredTask = class {
|
|
988
|
+
constructor(_ctx, _callback) {
|
|
989
|
+
this._ctx = _ctx;
|
|
990
|
+
this._callback = _callback;
|
|
991
|
+
this._scheduled = false;
|
|
992
|
+
this._currentTask = null;
|
|
993
|
+
this._nextTask = new Trigger();
|
|
994
|
+
}
|
|
995
|
+
get scheduled() {
|
|
996
|
+
return this._scheduled;
|
|
795
997
|
}
|
|
796
998
|
/**
|
|
797
|
-
*
|
|
798
|
-
* Caller is responsible for releasing the lock using the returned callback.
|
|
799
|
-
* NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
|
|
800
|
-
* @returns Release callback
|
|
999
|
+
* Schedule the task to run asynchronously.
|
|
801
1000
|
*/
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
this.
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
1001
|
+
schedule() {
|
|
1002
|
+
if (this._scheduled) {
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
scheduleTask(this._ctx, async () => {
|
|
1006
|
+
await this._currentTask;
|
|
1007
|
+
this._scheduled = false;
|
|
1008
|
+
const completionTrigger = this._nextTask;
|
|
1009
|
+
this._nextTask = new Trigger();
|
|
1010
|
+
this._currentTask = runInContextAsync(this._ctx, () => this._callback()).then(() => {
|
|
1011
|
+
completionTrigger.wake();
|
|
811
1012
|
});
|
|
812
1013
|
});
|
|
813
|
-
|
|
814
|
-
if (tag !== void 0) {
|
|
815
|
-
this._tag = tag;
|
|
816
|
-
}
|
|
817
|
-
return guard;
|
|
1014
|
+
this._scheduled = true;
|
|
818
1015
|
}
|
|
819
1016
|
/**
|
|
820
|
-
*
|
|
821
|
-
* Only a single function can be executed at a time.
|
|
822
|
-
* Function are executed in the same order as `executeSynchronized` is called.
|
|
823
|
-
* WARNING: Calling `executeSynchronized` inside of `executeSynchronized` on the same lock instance is a deadlock.
|
|
1017
|
+
* Schedule the task to run and wait for it to finish.
|
|
824
1018
|
*/
|
|
825
|
-
async
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
return await fun();
|
|
829
|
-
} finally {
|
|
830
|
-
guard.release();
|
|
1019
|
+
async runBlocking() {
|
|
1020
|
+
if (this._ctx.disposed) {
|
|
1021
|
+
throw new import_context4.ContextDisposedError();
|
|
831
1022
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
var MutexGuard = class {
|
|
835
|
-
constructor(_release) {
|
|
836
|
-
this._release = _release;
|
|
1023
|
+
this.schedule();
|
|
1024
|
+
await this._nextTask.wait();
|
|
837
1025
|
}
|
|
838
1026
|
/**
|
|
839
|
-
*
|
|
1027
|
+
* Waits for the current task to finish if it is running.
|
|
1028
|
+
* Does not schedule a new task.
|
|
840
1029
|
*/
|
|
841
|
-
|
|
842
|
-
this.
|
|
1030
|
+
async join() {
|
|
1031
|
+
await this._currentTask;
|
|
843
1032
|
}
|
|
844
|
-
|
|
845
|
-
|
|
1033
|
+
};
|
|
1034
|
+
var runInContext = (ctx, fn) => {
|
|
1035
|
+
try {
|
|
1036
|
+
fn();
|
|
1037
|
+
} catch (err) {
|
|
1038
|
+
ctx.raise(err);
|
|
846
1039
|
}
|
|
847
1040
|
};
|
|
848
|
-
var
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
if (
|
|
858
|
-
|
|
859
|
-
} else {
|
|
860
|
-
guard = await (0, import_debug.warnAfterTimeout)(1e4, `lock on ${tag} (taken by ${mutex.tag})`, () => mutex.acquire(tag));
|
|
1041
|
+
var runInContextAsync = async (ctx, fn) => {
|
|
1042
|
+
try {
|
|
1043
|
+
await fn();
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
ctx.raise(err);
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
var scheduleMicroTask = (ctx, fn) => {
|
|
1049
|
+
queueMicrotask(async () => {
|
|
1050
|
+
if (ctx.disposed) {
|
|
1051
|
+
return;
|
|
861
1052
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1053
|
+
await runInContextAsync(ctx, fn);
|
|
1054
|
+
});
|
|
1055
|
+
};
|
|
1056
|
+
var scheduleTask = (ctx, fn, afterMs) => {
|
|
1057
|
+
const clearTracking = trackResource(() => ({
|
|
1058
|
+
name: `task (${fn.name || "anonymous"})`,
|
|
1059
|
+
openStack: new import_debug3.StackTrace()
|
|
1060
|
+
}));
|
|
1061
|
+
const timeout = setTimeout(async () => {
|
|
1062
|
+
clearDispose();
|
|
1063
|
+
await runInContextAsync(ctx, fn);
|
|
1064
|
+
clearTracking();
|
|
1065
|
+
}, afterMs);
|
|
1066
|
+
const clearDispose = ctx.onDispose(() => {
|
|
1067
|
+
clearTracking();
|
|
1068
|
+
clearTimeout(timeout);
|
|
1069
|
+
});
|
|
1070
|
+
};
|
|
1071
|
+
var scheduleTaskInterval = (ctx, task, interval) => {
|
|
1072
|
+
const clearTracking = trackResource(() => ({
|
|
1073
|
+
name: `repeating task (${task.name || "anonymous"})`,
|
|
1074
|
+
openStack: new import_debug3.StackTrace()
|
|
1075
|
+
}));
|
|
1076
|
+
let timeoutId;
|
|
1077
|
+
const run = async () => {
|
|
1078
|
+
await runInContextAsync(ctx, task);
|
|
1079
|
+
if (ctx.disposed) {
|
|
1080
|
+
return;
|
|
866
1081
|
}
|
|
1082
|
+
timeoutId = setTimeout(run, interval);
|
|
867
1083
|
};
|
|
868
|
-
|
|
869
|
-
|
|
1084
|
+
timeoutId = setTimeout(run, interval);
|
|
1085
|
+
ctx.onDispose(() => {
|
|
1086
|
+
clearTracking();
|
|
1087
|
+
clearTimeout(timeoutId);
|
|
870
1088
|
});
|
|
871
1089
|
};
|
|
1090
|
+
var scheduleExponentialBackoffTaskInterval = (ctx, task, initialInterval) => {
|
|
1091
|
+
const clearTracking = trackResource(() => ({
|
|
1092
|
+
name: `repeating task (${task.name || "anonymous"})`,
|
|
1093
|
+
openStack: new import_debug3.StackTrace()
|
|
1094
|
+
}));
|
|
1095
|
+
let timeoutId;
|
|
1096
|
+
let interval = initialInterval;
|
|
1097
|
+
const repeat = async () => {
|
|
1098
|
+
await runInContextAsync(ctx, task);
|
|
1099
|
+
if (ctx.disposed) {
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
interval *= 2;
|
|
1103
|
+
timeoutId = setTimeout(repeat, interval);
|
|
1104
|
+
};
|
|
1105
|
+
timeoutId = setTimeout(repeat, interval);
|
|
1106
|
+
ctx.onDispose(() => {
|
|
1107
|
+
clearTracking();
|
|
1108
|
+
clearTimeout(timeoutId);
|
|
1109
|
+
});
|
|
1110
|
+
};
|
|
1111
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
1112
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1113
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1114
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1115
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1116
|
+
}
|
|
1117
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/common/async/src/persistent-lifecycle.ts";
|
|
1118
|
+
var INIT_RESTART_DELAY = 100;
|
|
1119
|
+
var DEFAULT_MAX_RESTART_DELAY = 5e3;
|
|
1120
|
+
var PersistentLifecycle = class extends import_context3.Resource {
|
|
1121
|
+
constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }) {
|
|
1122
|
+
super();
|
|
1123
|
+
this._currentState = void 0;
|
|
1124
|
+
this._restartTask = void 0;
|
|
1125
|
+
this._restartAfter = 0;
|
|
1126
|
+
this._start = start;
|
|
1127
|
+
this._stop = stop;
|
|
1128
|
+
this._onRestart = onRestart;
|
|
1129
|
+
this._maxRestartDelay = maxRestartDelay;
|
|
1130
|
+
}
|
|
1131
|
+
get state() {
|
|
1132
|
+
return this._currentState;
|
|
1133
|
+
}
|
|
1134
|
+
async _open() {
|
|
1135
|
+
this._restartTask = new DeferredTask(this._ctx, async () => {
|
|
1136
|
+
try {
|
|
1137
|
+
await this._restart();
|
|
1138
|
+
} catch (err) {
|
|
1139
|
+
import_log.log.warn("Restart failed", {
|
|
1140
|
+
err
|
|
1141
|
+
}, {
|
|
1142
|
+
F: __dxlog_file4,
|
|
1143
|
+
L: 72,
|
|
1144
|
+
S: this,
|
|
1145
|
+
C: (f, a) => f(...a)
|
|
1146
|
+
});
|
|
1147
|
+
this._restartTask?.schedule();
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
this._currentState = await this._start().catch((err) => {
|
|
1151
|
+
import_log.log.warn("Start failed", {
|
|
1152
|
+
err
|
|
1153
|
+
}, {
|
|
1154
|
+
F: __dxlog_file4,
|
|
1155
|
+
L: 77,
|
|
1156
|
+
S: this,
|
|
1157
|
+
C: (f, a) => f(...a)
|
|
1158
|
+
});
|
|
1159
|
+
this._restartTask?.schedule();
|
|
1160
|
+
return void 0;
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
async _close() {
|
|
1164
|
+
await this._restartTask?.join();
|
|
1165
|
+
await this._stopCurrentState();
|
|
1166
|
+
this._restartTask = void 0;
|
|
1167
|
+
}
|
|
1168
|
+
async _restart() {
|
|
1169
|
+
(0, import_log.log)(`restarting in ${this._restartAfter}ms`, {
|
|
1170
|
+
state: this._lifecycleState
|
|
1171
|
+
}, {
|
|
1172
|
+
F: __dxlog_file4,
|
|
1173
|
+
L: 90,
|
|
1174
|
+
S: this,
|
|
1175
|
+
C: (f, a) => f(...a)
|
|
1176
|
+
});
|
|
1177
|
+
await this._stopCurrentState();
|
|
1178
|
+
if (this._lifecycleState !== import_context3.LifecycleState.OPEN) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
await (0, import_context3.cancelWithContext)(this._ctx, sleep(this._restartAfter));
|
|
1182
|
+
this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);
|
|
1183
|
+
await (0, import_debug2.warnAfterTimeout)(5e3, "Connection establishment takes too long", async () => {
|
|
1184
|
+
this._currentState = await this._start();
|
|
1185
|
+
});
|
|
1186
|
+
this._restartAfter = 0;
|
|
1187
|
+
await this._onRestart?.();
|
|
1188
|
+
}
|
|
1189
|
+
async _stopCurrentState() {
|
|
1190
|
+
if (this._currentState) {
|
|
1191
|
+
try {
|
|
1192
|
+
await this._stop(this._currentState);
|
|
1193
|
+
} catch (err) {
|
|
1194
|
+
import_log.log.catch(err, void 0, {
|
|
1195
|
+
F: __dxlog_file4,
|
|
1196
|
+
L: 112,
|
|
1197
|
+
S: this,
|
|
1198
|
+
C: (f, a) => f(...a)
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
this._currentState = void 0;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Scheduling restart should be done from outside.
|
|
1206
|
+
*/
|
|
1207
|
+
scheduleRestart() {
|
|
1208
|
+
if (this._lifecycleState !== import_context3.LifecycleState.OPEN) {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
this._restartTask.schedule();
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
_ts_decorate([
|
|
1215
|
+
synchronized
|
|
1216
|
+
], PersistentLifecycle.prototype, "_open", null);
|
|
1217
|
+
_ts_decorate([
|
|
1218
|
+
synchronized
|
|
1219
|
+
], PersistentLifecycle.prototype, "scheduleRestart", null);
|
|
872
1220
|
var sink = (emitter, event, count = 1) => {
|
|
873
1221
|
const [getPromise, resolve] = trigger();
|
|
874
1222
|
let counter = 0;
|
|
@@ -921,6 +1269,58 @@ var streamToArray = (stream) => {
|
|
|
921
1269
|
}
|
|
922
1270
|
return deferred;
|
|
923
1271
|
};
|
|
1272
|
+
var TestStream = class extends import_node_stream.Duplex {
|
|
1273
|
+
constructor() {
|
|
1274
|
+
super(...arguments);
|
|
1275
|
+
this._received = Buffer.alloc(0);
|
|
1276
|
+
this._onWrite = new Event();
|
|
1277
|
+
}
|
|
1278
|
+
static async assertConnectivity(stream1, stream2, { timeout = 200 } = {}) {
|
|
1279
|
+
stream1.push("ping");
|
|
1280
|
+
stream2.push("pong");
|
|
1281
|
+
await Promise.all([
|
|
1282
|
+
stream2.assertReceivedAsync("ping", {
|
|
1283
|
+
timeout
|
|
1284
|
+
}),
|
|
1285
|
+
stream1.assertReceivedAsync("pong", {
|
|
1286
|
+
timeout
|
|
1287
|
+
})
|
|
1288
|
+
]);
|
|
1289
|
+
}
|
|
1290
|
+
_write(chunk, encoding, callback) {
|
|
1291
|
+
this._received = Buffer.concat([
|
|
1292
|
+
this._received,
|
|
1293
|
+
chunk
|
|
1294
|
+
]);
|
|
1295
|
+
this._onWrite.emit();
|
|
1296
|
+
callback();
|
|
1297
|
+
}
|
|
1298
|
+
_read(size) {
|
|
1299
|
+
}
|
|
1300
|
+
assertReceivedAsync(data, { timeout = 200 } = {}) {
|
|
1301
|
+
const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1302
|
+
return asyncTimeout(this._onWrite.waitForCondition(() => this._received.equals(dataBuffer)), timeout);
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
var waitForCondition = ({ condition, timeout = 0, interval = 10, error }) => {
|
|
1306
|
+
const stopTime = timeout ? Date.now() + timeout : 0;
|
|
1307
|
+
const trigger2 = new Trigger();
|
|
1308
|
+
const waiter = async () => {
|
|
1309
|
+
while (!stopTime || Date.now() < stopTime) {
|
|
1310
|
+
try {
|
|
1311
|
+
const value = await condition();
|
|
1312
|
+
if (value) {
|
|
1313
|
+
trigger2.wake(value);
|
|
1314
|
+
break;
|
|
1315
|
+
}
|
|
1316
|
+
} catch (err) {
|
|
1317
|
+
}
|
|
1318
|
+
await sleep(interval);
|
|
1319
|
+
}
|
|
1320
|
+
};
|
|
1321
|
+
setTimeout(waiter, 0);
|
|
1322
|
+
return timeout ? asyncTimeout(trigger2.wait(), timeout, error ?? new Error("Timeout")) : trigger2.wait();
|
|
1323
|
+
};
|
|
924
1324
|
var Timer = class {
|
|
925
1325
|
constructor(_callback) {
|
|
926
1326
|
this._callback = _callback;
|
|
@@ -967,25 +1367,6 @@ var Timer = class {
|
|
|
967
1367
|
return this;
|
|
968
1368
|
}
|
|
969
1369
|
};
|
|
970
|
-
var waitForCondition = ({ condition, timeout = 0, interval = 10, error }) => {
|
|
971
|
-
const stopTime = timeout ? Date.now() + timeout : 0;
|
|
972
|
-
const trigger2 = new Trigger();
|
|
973
|
-
const waiter = async () => {
|
|
974
|
-
while (!stopTime || Date.now() < stopTime) {
|
|
975
|
-
try {
|
|
976
|
-
const value = await condition();
|
|
977
|
-
if (value) {
|
|
978
|
-
trigger2.wake(value);
|
|
979
|
-
break;
|
|
980
|
-
}
|
|
981
|
-
} catch (err) {
|
|
982
|
-
}
|
|
983
|
-
await sleep(interval);
|
|
984
|
-
}
|
|
985
|
-
};
|
|
986
|
-
setTimeout(waiter, 0);
|
|
987
|
-
return timeout ? asyncTimeout(trigger2.wait(), timeout, error ?? new Error("Timeout")) : trigger2.wait();
|
|
988
|
-
};
|
|
989
1370
|
var until = (cb, timeout) => {
|
|
990
1371
|
return new Promise((resolve, reject) => {
|
|
991
1372
|
const t = timeout && setTimeout(() => {
|
|
@@ -1019,240 +1400,6 @@ var untilError = (cb) => {
|
|
|
1019
1400
|
});
|
|
1020
1401
|
});
|
|
1021
1402
|
};
|
|
1022
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/async/src/track-leaks.ts";
|
|
1023
|
-
var enabled = typeof process !== "undefined" && !!process.env.DX_TRACK_LEAKS;
|
|
1024
|
-
var openResources = /* @__PURE__ */ new Set();
|
|
1025
|
-
var handleSymbol = Symbol("checkLeaksHandle");
|
|
1026
|
-
var trackResource = (resourceProvider) => {
|
|
1027
|
-
if (!enabled) {
|
|
1028
|
-
return () => {
|
|
1029
|
-
};
|
|
1030
|
-
}
|
|
1031
|
-
const resource = resourceProvider();
|
|
1032
|
-
openResources.add(resource);
|
|
1033
|
-
return () => {
|
|
1034
|
-
openResources.delete(resource);
|
|
1035
|
-
};
|
|
1036
|
-
};
|
|
1037
|
-
var trackLeaks = (open, close) => (target) => {
|
|
1038
|
-
if (!enabled) {
|
|
1039
|
-
return;
|
|
1040
|
-
}
|
|
1041
|
-
const openMethod = target.prototype[open];
|
|
1042
|
-
const closeMethod = target.prototype[close];
|
|
1043
|
-
if (!openMethod || !closeMethod) {
|
|
1044
|
-
throw new Error(`Cannot find ${open} or ${close} method in ${target.name}`);
|
|
1045
|
-
}
|
|
1046
|
-
{
|
|
1047
|
-
target.prototype[open] = async function(...args) {
|
|
1048
|
-
this[handleSymbol] = trackResource(() => ({
|
|
1049
|
-
name: target.name,
|
|
1050
|
-
openStack: new import_debug3.StackTrace()
|
|
1051
|
-
}));
|
|
1052
|
-
return openMethod.apply(this, args);
|
|
1053
|
-
};
|
|
1054
|
-
Object.defineProperty(target.prototype[open], "name", {
|
|
1055
|
-
value: open + "$checkLeaks"
|
|
1056
|
-
});
|
|
1057
|
-
}
|
|
1058
|
-
{
|
|
1059
|
-
target.prototype[close] = async function(...args) {
|
|
1060
|
-
this[handleSymbol]?.();
|
|
1061
|
-
return closeMethod.apply(this, args);
|
|
1062
|
-
};
|
|
1063
|
-
Object.defineProperty(target.prototype[close], "name", {
|
|
1064
|
-
value: close + "$checkLeaks"
|
|
1065
|
-
});
|
|
1066
|
-
}
|
|
1067
|
-
};
|
|
1068
|
-
var dumpLeaks = () => {
|
|
1069
|
-
if (!enabled) {
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
import_log.log.info(`Leaked resources ${openResources.size}:`, void 0, {
|
|
1073
|
-
F: __dxlog_file3,
|
|
1074
|
-
L: 82,
|
|
1075
|
-
S: void 0,
|
|
1076
|
-
C: (f, a) => f(...a)
|
|
1077
|
-
});
|
|
1078
|
-
for (const resource of openResources) {
|
|
1079
|
-
import_log.log.info(`- ${resource.name} at`, void 0, {
|
|
1080
|
-
F: __dxlog_file3,
|
|
1081
|
-
L: 84,
|
|
1082
|
-
S: void 0,
|
|
1083
|
-
C: (f, a) => f(...a)
|
|
1084
|
-
});
|
|
1085
|
-
import_log.log.info(resource.openStack.getStack(1), void 0, {
|
|
1086
|
-
F: __dxlog_file3,
|
|
1087
|
-
L: 85,
|
|
1088
|
-
S: void 0,
|
|
1089
|
-
C: (f, a) => f(...a)
|
|
1090
|
-
});
|
|
1091
|
-
import_log.log.info("\n", void 0, {
|
|
1092
|
-
F: __dxlog_file3,
|
|
1093
|
-
L: 86,
|
|
1094
|
-
S: void 0,
|
|
1095
|
-
C: (f, a) => f(...a)
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
};
|
|
1099
|
-
if (enabled) {
|
|
1100
|
-
global.dxDumpLeaks = dumpLeaks;
|
|
1101
|
-
}
|
|
1102
|
-
var DeferredTask = class {
|
|
1103
|
-
constructor(_ctx, _callback) {
|
|
1104
|
-
this._ctx = _ctx;
|
|
1105
|
-
this._callback = _callback;
|
|
1106
|
-
this._scheduled = false;
|
|
1107
|
-
this._currentTask = null;
|
|
1108
|
-
this._nextTask = new Trigger();
|
|
1109
|
-
}
|
|
1110
|
-
/**
|
|
1111
|
-
* Schedule the task to run asynchronously.
|
|
1112
|
-
*/
|
|
1113
|
-
schedule() {
|
|
1114
|
-
if (this._scheduled) {
|
|
1115
|
-
return;
|
|
1116
|
-
}
|
|
1117
|
-
scheduleTask(this._ctx, async () => {
|
|
1118
|
-
await this._currentTask;
|
|
1119
|
-
this._scheduled = false;
|
|
1120
|
-
const completionTrigger = this._nextTask;
|
|
1121
|
-
this._nextTask = new Trigger();
|
|
1122
|
-
this._currentTask = runInContextAsync(this._ctx, () => this._callback()).then(() => {
|
|
1123
|
-
completionTrigger.wake();
|
|
1124
|
-
});
|
|
1125
|
-
});
|
|
1126
|
-
this._scheduled = true;
|
|
1127
|
-
}
|
|
1128
|
-
/**
|
|
1129
|
-
* Schedule the task to run and wait for it to finish.
|
|
1130
|
-
*/
|
|
1131
|
-
async runBlocking() {
|
|
1132
|
-
if (this._ctx.disposed) {
|
|
1133
|
-
throw new import_context3.ContextDisposedError();
|
|
1134
|
-
}
|
|
1135
|
-
this.schedule();
|
|
1136
|
-
await this._nextTask.wait();
|
|
1137
|
-
}
|
|
1138
|
-
/**
|
|
1139
|
-
* Waits for the current task to finish if it is running.
|
|
1140
|
-
* Does not schedule a new task.
|
|
1141
|
-
*/
|
|
1142
|
-
async join() {
|
|
1143
|
-
await this._currentTask;
|
|
1144
|
-
}
|
|
1145
|
-
};
|
|
1146
|
-
var runInContext = (ctx, fn) => {
|
|
1147
|
-
try {
|
|
1148
|
-
fn();
|
|
1149
|
-
} catch (err) {
|
|
1150
|
-
ctx.raise(err);
|
|
1151
|
-
}
|
|
1152
|
-
};
|
|
1153
|
-
var runInContextAsync = async (ctx, fn) => {
|
|
1154
|
-
try {
|
|
1155
|
-
await fn();
|
|
1156
|
-
} catch (err) {
|
|
1157
|
-
ctx.raise(err);
|
|
1158
|
-
}
|
|
1159
|
-
};
|
|
1160
|
-
var scheduleMicroTask = (ctx, fn) => {
|
|
1161
|
-
queueMicrotask(async () => {
|
|
1162
|
-
if (ctx.disposed) {
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
await runInContextAsync(ctx, fn);
|
|
1166
|
-
});
|
|
1167
|
-
};
|
|
1168
|
-
var scheduleTask = (ctx, fn, afterMs) => {
|
|
1169
|
-
const clearTracking = trackResource(() => ({
|
|
1170
|
-
name: `task (${fn.name || "anonymous"})`,
|
|
1171
|
-
openStack: new import_debug2.StackTrace()
|
|
1172
|
-
}));
|
|
1173
|
-
const timeout = setTimeout(async () => {
|
|
1174
|
-
clearDispose();
|
|
1175
|
-
await runInContextAsync(ctx, fn);
|
|
1176
|
-
clearTracking();
|
|
1177
|
-
}, afterMs);
|
|
1178
|
-
const clearDispose = ctx.onDispose(() => {
|
|
1179
|
-
clearTracking();
|
|
1180
|
-
clearTimeout(timeout);
|
|
1181
|
-
});
|
|
1182
|
-
};
|
|
1183
|
-
var scheduleTaskInterval = (ctx, task, interval) => {
|
|
1184
|
-
const clearTracking = trackResource(() => ({
|
|
1185
|
-
name: `repeating task (${task.name || "anonymous"})`,
|
|
1186
|
-
openStack: new import_debug2.StackTrace()
|
|
1187
|
-
}));
|
|
1188
|
-
let timeoutId;
|
|
1189
|
-
const run = async () => {
|
|
1190
|
-
await runInContextAsync(ctx, task);
|
|
1191
|
-
if (ctx.disposed) {
|
|
1192
|
-
return;
|
|
1193
|
-
}
|
|
1194
|
-
timeoutId = setTimeout(run, interval);
|
|
1195
|
-
};
|
|
1196
|
-
timeoutId = setTimeout(run, interval);
|
|
1197
|
-
ctx.onDispose(() => {
|
|
1198
|
-
clearTracking();
|
|
1199
|
-
clearTimeout(timeoutId);
|
|
1200
|
-
});
|
|
1201
|
-
};
|
|
1202
|
-
var scheduleExponentialBackoffTaskInterval = (ctx, task, initialInterval) => {
|
|
1203
|
-
const clearTracking = trackResource(() => ({
|
|
1204
|
-
name: `repeating task (${task.name || "anonymous"})`,
|
|
1205
|
-
openStack: new import_debug2.StackTrace()
|
|
1206
|
-
}));
|
|
1207
|
-
let timeoutId;
|
|
1208
|
-
let interval = initialInterval;
|
|
1209
|
-
const repeat = async () => {
|
|
1210
|
-
await runInContextAsync(ctx, task);
|
|
1211
|
-
if (ctx.disposed) {
|
|
1212
|
-
return;
|
|
1213
|
-
}
|
|
1214
|
-
interval *= 2;
|
|
1215
|
-
timeoutId = setTimeout(repeat, interval);
|
|
1216
|
-
};
|
|
1217
|
-
timeoutId = setTimeout(repeat, interval);
|
|
1218
|
-
ctx.onDispose(() => {
|
|
1219
|
-
clearTracking();
|
|
1220
|
-
clearTimeout(timeoutId);
|
|
1221
|
-
});
|
|
1222
|
-
};
|
|
1223
|
-
var TestStream = class extends import_node_stream.Duplex {
|
|
1224
|
-
constructor() {
|
|
1225
|
-
super(...arguments);
|
|
1226
|
-
this._received = Buffer.alloc(0);
|
|
1227
|
-
this._onWrite = new Event();
|
|
1228
|
-
}
|
|
1229
|
-
static async assertConnectivity(stream1, stream2, { timeout = 200 } = {}) {
|
|
1230
|
-
stream1.push("ping");
|
|
1231
|
-
stream2.push("pong");
|
|
1232
|
-
await Promise.all([
|
|
1233
|
-
stream2.assertReceivedAsync("ping", {
|
|
1234
|
-
timeout
|
|
1235
|
-
}),
|
|
1236
|
-
stream1.assertReceivedAsync("pong", {
|
|
1237
|
-
timeout
|
|
1238
|
-
})
|
|
1239
|
-
]);
|
|
1240
|
-
}
|
|
1241
|
-
_write(chunk, encoding, callback) {
|
|
1242
|
-
this._received = Buffer.concat([
|
|
1243
|
-
this._received,
|
|
1244
|
-
chunk
|
|
1245
|
-
]);
|
|
1246
|
-
this._onWrite.emit();
|
|
1247
|
-
callback();
|
|
1248
|
-
}
|
|
1249
|
-
_read(size) {
|
|
1250
|
-
}
|
|
1251
|
-
assertReceivedAsync(data, { timeout = 200 } = {}) {
|
|
1252
|
-
const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1253
|
-
return asyncTimeout(this._onWrite.waitForCondition(() => this._received.equals(dataBuffer)), timeout);
|
|
1254
|
-
}
|
|
1255
|
-
};
|
|
1256
1403
|
var TIME_PERIOD = 1e3;
|
|
1257
1404
|
var UpdateScheduler = class {
|
|
1258
1405
|
constructor(_ctx, _callback, _params = {}) {
|
|
@@ -1334,6 +1481,7 @@ var UpdateScheduler = class {
|
|
|
1334
1481
|
MutexGuard,
|
|
1335
1482
|
Observable,
|
|
1336
1483
|
ObservableProvider,
|
|
1484
|
+
PersistentLifecycle,
|
|
1337
1485
|
PushStream,
|
|
1338
1486
|
TestStream,
|
|
1339
1487
|
TimeoutError,
|