@dxos/async 0.7.5-labs.ea4b4c2 → 0.7.5-labs.f400bbc
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 +458 -341
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +440 -326
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +458 -341
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +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/package.json +8 -7
- package/src/index.ts +6 -5
- package/src/persistent-lifecycle.test.ts +77 -0
- package/src/persistent-lifecycle.ts +128 -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) => {
|
|
@@ -578,6 +582,94 @@ var latch = ({ count = 1, timeout } = {}) => {
|
|
|
578
582
|
(err) => doReject(err)
|
|
579
583
|
];
|
|
580
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
|
+
};
|
|
581
673
|
var trigger = (timeout) => {
|
|
582
674
|
let callback;
|
|
583
675
|
const promise = new Promise((resolve, reject) => {
|
|
@@ -771,7 +863,7 @@ var EMPTY_OBSERVABLE = MulticastObservable.of(null);
|
|
|
771
863
|
var ObservableProvider = class {
|
|
772
864
|
constructor() {
|
|
773
865
|
this._handlers = /* @__PURE__ */ new Set();
|
|
774
|
-
this._proxy = (0,
|
|
866
|
+
this._proxy = (0, import_util2.createSetDispatch)({
|
|
775
867
|
handlers: this._handlers
|
|
776
868
|
});
|
|
777
869
|
}
|
|
@@ -812,94 +904,319 @@ var CancellableObservableProvider = class extends ObservableProvider {
|
|
|
812
904
|
this.callback.onCancelled?.();
|
|
813
905
|
}
|
|
814
906
|
};
|
|
815
|
-
var
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
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
|
+
};
|
|
820
915
|
}
|
|
821
|
-
|
|
822
|
-
|
|
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;
|
|
823
925
|
}
|
|
824
|
-
|
|
825
|
-
|
|
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;
|
|
826
997
|
}
|
|
827
998
|
/**
|
|
828
|
-
*
|
|
829
|
-
* Caller is responsible for releasing the lock using the returned callback.
|
|
830
|
-
* NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
|
|
831
|
-
* @returns Release callback
|
|
999
|
+
* Schedule the task to run asynchronously.
|
|
832
1000
|
*/
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
this.
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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();
|
|
842
1012
|
});
|
|
843
1013
|
});
|
|
844
|
-
|
|
845
|
-
if (tag !== void 0) {
|
|
846
|
-
this._tag = tag;
|
|
847
|
-
}
|
|
848
|
-
return guard;
|
|
1014
|
+
this._scheduled = true;
|
|
849
1015
|
}
|
|
850
1016
|
/**
|
|
851
|
-
*
|
|
852
|
-
* Only a single function can be executed at a time.
|
|
853
|
-
* Function are executed in the same order as `executeSynchronized` is called.
|
|
854
|
-
* 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.
|
|
855
1018
|
*/
|
|
856
|
-
async
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
return await fun();
|
|
860
|
-
} finally {
|
|
861
|
-
guard.release();
|
|
1019
|
+
async runBlocking() {
|
|
1020
|
+
if (this._ctx.disposed) {
|
|
1021
|
+
throw new import_context4.ContextDisposedError();
|
|
862
1022
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
var MutexGuard = class {
|
|
866
|
-
constructor(_release) {
|
|
867
|
-
this._release = _release;
|
|
1023
|
+
this.schedule();
|
|
1024
|
+
await this._nextTask.wait();
|
|
868
1025
|
}
|
|
869
1026
|
/**
|
|
870
|
-
*
|
|
1027
|
+
* Waits for the current task to finish if it is running.
|
|
1028
|
+
* Does not schedule a new task.
|
|
871
1029
|
*/
|
|
872
|
-
|
|
873
|
-
this.
|
|
1030
|
+
async join() {
|
|
1031
|
+
await this._currentTask;
|
|
874
1032
|
}
|
|
875
|
-
|
|
876
|
-
|
|
1033
|
+
};
|
|
1034
|
+
var runInContext = (ctx, fn) => {
|
|
1035
|
+
try {
|
|
1036
|
+
fn();
|
|
1037
|
+
} catch (err) {
|
|
1038
|
+
ctx.raise(err);
|
|
877
1039
|
}
|
|
878
1040
|
};
|
|
879
|
-
var
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
if (
|
|
889
|
-
|
|
890
|
-
} else {
|
|
891
|
-
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;
|
|
892
1052
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
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;
|
|
1081
|
+
}
|
|
1082
|
+
timeoutId = setTimeout(run, interval);
|
|
1083
|
+
};
|
|
1084
|
+
timeoutId = setTimeout(run, interval);
|
|
1085
|
+
ctx.onDispose(() => {
|
|
1086
|
+
clearTracking();
|
|
1087
|
+
clearTimeout(timeoutId);
|
|
1088
|
+
});
|
|
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;
|
|
897
1101
|
}
|
|
1102
|
+
interval *= 2;
|
|
1103
|
+
timeoutId = setTimeout(repeat, interval);
|
|
898
1104
|
};
|
|
899
|
-
|
|
900
|
-
|
|
1105
|
+
timeoutId = setTimeout(repeat, interval);
|
|
1106
|
+
ctx.onDispose(() => {
|
|
1107
|
+
clearTracking();
|
|
1108
|
+
clearTimeout(timeoutId);
|
|
901
1109
|
});
|
|
902
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);
|
|
903
1220
|
var sink = (emitter, event, count = 1) => {
|
|
904
1221
|
const [getPromise, resolve] = trigger();
|
|
905
1222
|
let counter = 0;
|
|
@@ -952,6 +1269,58 @@ var streamToArray = (stream) => {
|
|
|
952
1269
|
}
|
|
953
1270
|
return deferred;
|
|
954
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
|
+
};
|
|
955
1324
|
var Timer = class {
|
|
956
1325
|
constructor(_callback) {
|
|
957
1326
|
this._callback = _callback;
|
|
@@ -998,25 +1367,6 @@ var Timer = class {
|
|
|
998
1367
|
return this;
|
|
999
1368
|
}
|
|
1000
1369
|
};
|
|
1001
|
-
var waitForCondition = ({ condition, timeout = 0, interval = 10, error }) => {
|
|
1002
|
-
const stopTime = timeout ? Date.now() + timeout : 0;
|
|
1003
|
-
const trigger2 = new Trigger();
|
|
1004
|
-
const waiter = async () => {
|
|
1005
|
-
while (!stopTime || Date.now() < stopTime) {
|
|
1006
|
-
try {
|
|
1007
|
-
const value = await condition();
|
|
1008
|
-
if (value) {
|
|
1009
|
-
trigger2.wake(value);
|
|
1010
|
-
break;
|
|
1011
|
-
}
|
|
1012
|
-
} catch (err) {
|
|
1013
|
-
}
|
|
1014
|
-
await sleep(interval);
|
|
1015
|
-
}
|
|
1016
|
-
};
|
|
1017
|
-
setTimeout(waiter, 0);
|
|
1018
|
-
return timeout ? asyncTimeout(trigger2.wait(), timeout, error ?? new Error("Timeout")) : trigger2.wait();
|
|
1019
|
-
};
|
|
1020
1370
|
var until = (cb, timeout) => {
|
|
1021
1371
|
return new Promise((resolve, reject) => {
|
|
1022
1372
|
const t = timeout && setTimeout(() => {
|
|
@@ -1050,243 +1400,6 @@ var untilError = (cb) => {
|
|
|
1050
1400
|
});
|
|
1051
1401
|
});
|
|
1052
1402
|
};
|
|
1053
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/async/src/track-leaks.ts";
|
|
1054
|
-
var enabled = typeof process !== "undefined" && !!process.env.DX_TRACK_LEAKS;
|
|
1055
|
-
var openResources = /* @__PURE__ */ new Set();
|
|
1056
|
-
var handleSymbol = Symbol("checkLeaksHandle");
|
|
1057
|
-
var trackResource = (resourceProvider) => {
|
|
1058
|
-
if (!enabled) {
|
|
1059
|
-
return () => {
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
const resource = resourceProvider();
|
|
1063
|
-
openResources.add(resource);
|
|
1064
|
-
return () => {
|
|
1065
|
-
openResources.delete(resource);
|
|
1066
|
-
};
|
|
1067
|
-
};
|
|
1068
|
-
var trackLeaks = (open, close) => (target) => {
|
|
1069
|
-
if (!enabled) {
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
const openMethod = target.prototype[open];
|
|
1073
|
-
const closeMethod = target.prototype[close];
|
|
1074
|
-
if (!openMethod || !closeMethod) {
|
|
1075
|
-
throw new Error(`Cannot find ${open} or ${close} method in ${target.name}`);
|
|
1076
|
-
}
|
|
1077
|
-
{
|
|
1078
|
-
target.prototype[open] = async function(...args) {
|
|
1079
|
-
this[handleSymbol] = trackResource(() => ({
|
|
1080
|
-
name: target.name,
|
|
1081
|
-
openStack: new import_debug3.StackTrace()
|
|
1082
|
-
}));
|
|
1083
|
-
return openMethod.apply(this, args);
|
|
1084
|
-
};
|
|
1085
|
-
Object.defineProperty(target.prototype[open], "name", {
|
|
1086
|
-
value: open + "$checkLeaks"
|
|
1087
|
-
});
|
|
1088
|
-
}
|
|
1089
|
-
{
|
|
1090
|
-
target.prototype[close] = async function(...args) {
|
|
1091
|
-
this[handleSymbol]?.();
|
|
1092
|
-
return closeMethod.apply(this, args);
|
|
1093
|
-
};
|
|
1094
|
-
Object.defineProperty(target.prototype[close], "name", {
|
|
1095
|
-
value: close + "$checkLeaks"
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
};
|
|
1099
|
-
var dumpLeaks = () => {
|
|
1100
|
-
if (!enabled) {
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
import_log.log.info(`Leaked resources ${openResources.size}:`, void 0, {
|
|
1104
|
-
F: __dxlog_file3,
|
|
1105
|
-
L: 82,
|
|
1106
|
-
S: void 0,
|
|
1107
|
-
C: (f, a) => f(...a)
|
|
1108
|
-
});
|
|
1109
|
-
for (const resource of openResources) {
|
|
1110
|
-
import_log.log.info(`- ${resource.name} at`, void 0, {
|
|
1111
|
-
F: __dxlog_file3,
|
|
1112
|
-
L: 84,
|
|
1113
|
-
S: void 0,
|
|
1114
|
-
C: (f, a) => f(...a)
|
|
1115
|
-
});
|
|
1116
|
-
import_log.log.info(resource.openStack.getStack(1), void 0, {
|
|
1117
|
-
F: __dxlog_file3,
|
|
1118
|
-
L: 85,
|
|
1119
|
-
S: void 0,
|
|
1120
|
-
C: (f, a) => f(...a)
|
|
1121
|
-
});
|
|
1122
|
-
import_log.log.info("\n", void 0, {
|
|
1123
|
-
F: __dxlog_file3,
|
|
1124
|
-
L: 86,
|
|
1125
|
-
S: void 0,
|
|
1126
|
-
C: (f, a) => f(...a)
|
|
1127
|
-
});
|
|
1128
|
-
}
|
|
1129
|
-
};
|
|
1130
|
-
if (enabled) {
|
|
1131
|
-
global.dxDumpLeaks = dumpLeaks;
|
|
1132
|
-
}
|
|
1133
|
-
var DeferredTask = class {
|
|
1134
|
-
constructor(_ctx, _callback) {
|
|
1135
|
-
this._ctx = _ctx;
|
|
1136
|
-
this._callback = _callback;
|
|
1137
|
-
this._scheduled = false;
|
|
1138
|
-
this._currentTask = null;
|
|
1139
|
-
this._nextTask = new Trigger();
|
|
1140
|
-
}
|
|
1141
|
-
get scheduled() {
|
|
1142
|
-
return this._scheduled;
|
|
1143
|
-
}
|
|
1144
|
-
/**
|
|
1145
|
-
* Schedule the task to run asynchronously.
|
|
1146
|
-
*/
|
|
1147
|
-
schedule() {
|
|
1148
|
-
if (this._scheduled) {
|
|
1149
|
-
return;
|
|
1150
|
-
}
|
|
1151
|
-
scheduleTask(this._ctx, async () => {
|
|
1152
|
-
await this._currentTask;
|
|
1153
|
-
this._scheduled = false;
|
|
1154
|
-
const completionTrigger = this._nextTask;
|
|
1155
|
-
this._nextTask = new Trigger();
|
|
1156
|
-
this._currentTask = runInContextAsync(this._ctx, () => this._callback()).then(() => {
|
|
1157
|
-
completionTrigger.wake();
|
|
1158
|
-
});
|
|
1159
|
-
});
|
|
1160
|
-
this._scheduled = true;
|
|
1161
|
-
}
|
|
1162
|
-
/**
|
|
1163
|
-
* Schedule the task to run and wait for it to finish.
|
|
1164
|
-
*/
|
|
1165
|
-
async runBlocking() {
|
|
1166
|
-
if (this._ctx.disposed) {
|
|
1167
|
-
throw new import_context3.ContextDisposedError();
|
|
1168
|
-
}
|
|
1169
|
-
this.schedule();
|
|
1170
|
-
await this._nextTask.wait();
|
|
1171
|
-
}
|
|
1172
|
-
/**
|
|
1173
|
-
* Waits for the current task to finish if it is running.
|
|
1174
|
-
* Does not schedule a new task.
|
|
1175
|
-
*/
|
|
1176
|
-
async join() {
|
|
1177
|
-
await this._currentTask;
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
var runInContext = (ctx, fn) => {
|
|
1181
|
-
try {
|
|
1182
|
-
fn();
|
|
1183
|
-
} catch (err) {
|
|
1184
|
-
ctx.raise(err);
|
|
1185
|
-
}
|
|
1186
|
-
};
|
|
1187
|
-
var runInContextAsync = async (ctx, fn) => {
|
|
1188
|
-
try {
|
|
1189
|
-
await fn();
|
|
1190
|
-
} catch (err) {
|
|
1191
|
-
ctx.raise(err);
|
|
1192
|
-
}
|
|
1193
|
-
};
|
|
1194
|
-
var scheduleMicroTask = (ctx, fn) => {
|
|
1195
|
-
queueMicrotask(async () => {
|
|
1196
|
-
if (ctx.disposed) {
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
|
-
await runInContextAsync(ctx, fn);
|
|
1200
|
-
});
|
|
1201
|
-
};
|
|
1202
|
-
var scheduleTask = (ctx, fn, afterMs) => {
|
|
1203
|
-
const clearTracking = trackResource(() => ({
|
|
1204
|
-
name: `task (${fn.name || "anonymous"})`,
|
|
1205
|
-
openStack: new import_debug2.StackTrace()
|
|
1206
|
-
}));
|
|
1207
|
-
const timeout = setTimeout(async () => {
|
|
1208
|
-
clearDispose();
|
|
1209
|
-
await runInContextAsync(ctx, fn);
|
|
1210
|
-
clearTracking();
|
|
1211
|
-
}, afterMs);
|
|
1212
|
-
const clearDispose = ctx.onDispose(() => {
|
|
1213
|
-
clearTracking();
|
|
1214
|
-
clearTimeout(timeout);
|
|
1215
|
-
});
|
|
1216
|
-
};
|
|
1217
|
-
var scheduleTaskInterval = (ctx, task, interval) => {
|
|
1218
|
-
const clearTracking = trackResource(() => ({
|
|
1219
|
-
name: `repeating task (${task.name || "anonymous"})`,
|
|
1220
|
-
openStack: new import_debug2.StackTrace()
|
|
1221
|
-
}));
|
|
1222
|
-
let timeoutId;
|
|
1223
|
-
const run = async () => {
|
|
1224
|
-
await runInContextAsync(ctx, task);
|
|
1225
|
-
if (ctx.disposed) {
|
|
1226
|
-
return;
|
|
1227
|
-
}
|
|
1228
|
-
timeoutId = setTimeout(run, interval);
|
|
1229
|
-
};
|
|
1230
|
-
timeoutId = setTimeout(run, interval);
|
|
1231
|
-
ctx.onDispose(() => {
|
|
1232
|
-
clearTracking();
|
|
1233
|
-
clearTimeout(timeoutId);
|
|
1234
|
-
});
|
|
1235
|
-
};
|
|
1236
|
-
var scheduleExponentialBackoffTaskInterval = (ctx, task, initialInterval) => {
|
|
1237
|
-
const clearTracking = trackResource(() => ({
|
|
1238
|
-
name: `repeating task (${task.name || "anonymous"})`,
|
|
1239
|
-
openStack: new import_debug2.StackTrace()
|
|
1240
|
-
}));
|
|
1241
|
-
let timeoutId;
|
|
1242
|
-
let interval = initialInterval;
|
|
1243
|
-
const repeat = async () => {
|
|
1244
|
-
await runInContextAsync(ctx, task);
|
|
1245
|
-
if (ctx.disposed) {
|
|
1246
|
-
return;
|
|
1247
|
-
}
|
|
1248
|
-
interval *= 2;
|
|
1249
|
-
timeoutId = setTimeout(repeat, interval);
|
|
1250
|
-
};
|
|
1251
|
-
timeoutId = setTimeout(repeat, interval);
|
|
1252
|
-
ctx.onDispose(() => {
|
|
1253
|
-
clearTracking();
|
|
1254
|
-
clearTimeout(timeoutId);
|
|
1255
|
-
});
|
|
1256
|
-
};
|
|
1257
|
-
var TestStream = class extends import_node_stream.Duplex {
|
|
1258
|
-
constructor() {
|
|
1259
|
-
super(...arguments);
|
|
1260
|
-
this._received = Buffer.alloc(0);
|
|
1261
|
-
this._onWrite = new Event();
|
|
1262
|
-
}
|
|
1263
|
-
static async assertConnectivity(stream1, stream2, { timeout = 200 } = {}) {
|
|
1264
|
-
stream1.push("ping");
|
|
1265
|
-
stream2.push("pong");
|
|
1266
|
-
await Promise.all([
|
|
1267
|
-
stream2.assertReceivedAsync("ping", {
|
|
1268
|
-
timeout
|
|
1269
|
-
}),
|
|
1270
|
-
stream1.assertReceivedAsync("pong", {
|
|
1271
|
-
timeout
|
|
1272
|
-
})
|
|
1273
|
-
]);
|
|
1274
|
-
}
|
|
1275
|
-
_write(chunk, encoding, callback) {
|
|
1276
|
-
this._received = Buffer.concat([
|
|
1277
|
-
this._received,
|
|
1278
|
-
chunk
|
|
1279
|
-
]);
|
|
1280
|
-
this._onWrite.emit();
|
|
1281
|
-
callback();
|
|
1282
|
-
}
|
|
1283
|
-
_read(size) {
|
|
1284
|
-
}
|
|
1285
|
-
assertReceivedAsync(data, { timeout = 200 } = {}) {
|
|
1286
|
-
const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1287
|
-
return asyncTimeout(this._onWrite.waitForCondition(() => this._received.equals(dataBuffer)), timeout);
|
|
1288
|
-
}
|
|
1289
|
-
};
|
|
1290
1403
|
var TIME_PERIOD = 1e3;
|
|
1291
1404
|
var UpdateScheduler = class {
|
|
1292
1405
|
constructor(_ctx, _callback, _params = {}) {
|
|
@@ -1368,6 +1481,7 @@ var UpdateScheduler = class {
|
|
|
1368
1481
|
MutexGuard,
|
|
1369
1482
|
Observable,
|
|
1370
1483
|
ObservableProvider,
|
|
1484
|
+
PersistentLifecycle,
|
|
1371
1485
|
PushStream,
|
|
1372
1486
|
TestStream,
|
|
1373
1487
|
TimeoutError,
|