@harperfast/harper 5.3.0-alpha.1 → 5.3.0-beta.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/bin/cliOperations.ts +12 -0
- package/bin/restart.ts +66 -6
- package/components/Application.ts +1134 -112
- package/components/OptionsWatcher.ts +368 -102
- package/components/Scope.ts +20 -1
- package/components/componentLoader.ts +43 -4
- package/components/deploymentOperations.ts +4 -1
- package/components/deploymentRecorder.ts +9 -2
- package/components/operations.js +284 -52
- package/components/operationsValidation.js +49 -2
- package/components/packageComponent.ts +25 -1
- package/components/requestRestart.ts +11 -0
- package/config/RootConfigWatcher.ts +191 -37
- package/config/configReadRetry.ts +62 -0
- package/config/configUtils.ts +78 -26
- package/config/parseConfigFile.ts +34 -0
- package/config/readConfigFileSync.ts +44 -0
- package/config/watcherArming.ts +59 -0
- package/config-root.schema.json +4 -0
- package/dataLayer/harperBridge/ResourceBridge.ts +28 -2
- package/dist/bin/cliOperations.js +13 -0
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/restart.js +42 -6
- package/dist/bin/restart.js.map +1 -1
- package/dist/components/Application.d.ts +104 -9
- package/dist/components/Application.js +954 -102
- package/dist/components/Application.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +4 -1
- package/dist/components/OptionsWatcher.js +378 -104
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/Scope.js +15 -1
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/componentLoader.js +35 -3
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deploymentOperations.js +4 -1
- package/dist/components/deploymentOperations.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +4 -2
- package/dist/components/deploymentRecorder.js +1 -0
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/operations.d.ts +28 -0
- package/dist/components/operations.js +263 -54
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +48 -2
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/packageComponent.js +24 -0
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/components/requestRestart.d.ts +1 -0
- package/dist/components/requestRestart.js +7 -0
- package/dist/components/requestRestart.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +2 -0
- package/dist/config/RootConfigWatcher.js +189 -35
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configReadRetry.d.ts +8 -0
- package/dist/config/configReadRetry.js +62 -0
- package/dist/config/configReadRetry.js.map +1 -0
- package/dist/config/configUtils.d.ts +10 -9
- package/dist/config/configUtils.js +63 -27
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/parseConfigFile.d.ts +4 -0
- package/dist/config/parseConfigFile.js +35 -0
- package/dist/config/parseConfigFile.js.map +1 -0
- package/dist/config/readConfigFileSync.d.ts +1 -0
- package/dist/config/readConfigFileSync.js +47 -0
- package/dist/config/readConfigFileSync.js.map +1 -0
- package/dist/config/watcherArming.d.ts +15 -0
- package/dist/config/watcherArming.js +59 -0
- package/dist/config/watcherArming.js.map +1 -0
- package/dist/dataLayer/harperBridge/ResourceBridge.js +21 -2
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +3 -0
- package/dist/resources/DatabaseTransaction.d.ts +25 -0
- package/dist/resources/DatabaseTransaction.js +224 -18
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -1
- package/dist/resources/LMDBTransaction.js +22 -3
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.js +22 -6
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +1 -1
- package/dist/resources/RecordEncoder.js +21 -5
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/Resource.js +97 -13
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +8 -0
- package/dist/resources/RocksIndexStore.js +2 -1
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +10 -0
- package/dist/resources/RocksTransactionLogStore.js +104 -33
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +58 -7
- package/dist/resources/Table.js +1095 -346
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +10 -3
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +170 -0
- package/dist/resources/auditStore.js +457 -11
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/dataLoader.js +3 -4
- package/dist/resources/dataLoader.js.map +1 -1
- package/dist/resources/databases.d.ts +16 -13
- package/dist/resources/databases.js +624 -176
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +5 -0
- package/dist/resources/derivedIndexRegistry.js +68 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -0
- package/dist/resources/derivedIndexRuntime.d.ts +215 -0
- package/dist/resources/derivedIndexRuntime.js +2027 -0
- package/dist/resources/derivedIndexRuntime.js.map +1 -0
- package/dist/resources/graphql.js +3 -2
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +102 -9
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +848 -39
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
- package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
- package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
- package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
- package/dist/resources/nodeIdMapping.d.ts +5 -0
- package/dist/resources/nodeIdMapping.js +49 -0
- package/dist/resources/nodeIdMapping.js.map +1 -1
- package/dist/resources/recordLock.d.ts +47 -4
- package/dist/resources/recordLock.js +138 -7
- package/dist/resources/recordLock.js.map +1 -1
- package/dist/resources/recordLockCoordinator.d.ts +557 -0
- package/dist/resources/recordLockCoordinator.js +2565 -0
- package/dist/resources/recordLockCoordinator.js.map +1 -0
- package/dist/resources/replayLogs.js +5 -0
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replicatedApplyFailure.d.ts +16 -0
- package/dist/resources/replicatedApplyFailure.js +63 -0
- package/dist/resources/replicatedApplyFailure.js.map +1 -0
- package/dist/resources/scheduler/scheduler.js +3 -3
- package/dist/resources/scheduler/scheduler.js.map +1 -1
- package/dist/resources/search.d.ts +10 -4
- package/dist/resources/search.js +160 -40
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/tracked.d.ts +5 -1
- package/dist/resources/tracked.js +74 -23
- package/dist/resources/tracked.js.map +1 -1
- package/dist/security/jsLoader.js +6 -4
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/server/REST.js +33 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/http.d.ts +5 -1
- package/dist/server/http.js +34 -2
- package/dist/server/http.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +2 -0
- package/dist/server/serverHelpers/Headers.js +6 -0
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
- package/dist/server/serverHelpers/Request.d.ts +5 -10
- package/dist/server/serverHelpers/Request.js +38 -136
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +2 -0
- package/dist/server/serverHelpers/contentTypes.js +189 -15
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.js +96 -17
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/storageReclamation.js +1 -1
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/isolatedApplications.d.ts +47 -0
- package/dist/server/threads/isolatedApplications.js +171 -0
- package/dist/server/threads/isolatedApplications.js.map +1 -0
- package/dist/server/threads/logRotationTransport.d.ts +1 -0
- package/dist/server/threads/logRotationTransport.js +33 -0
- package/dist/server/threads/logRotationTransport.js.map +1 -0
- package/dist/server/threads/manageThreads.d.ts +64 -6
- package/dist/server/threads/manageThreads.js +261 -12
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -0
- package/dist/server/threads/socketRouter.js +196 -13
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadServer.js +30 -7
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +24 -0
- package/dist/utility/errors/hdbError.js +58 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/hdbTerms.d.ts +2 -0
- package/dist/utility/hdbTerms.js +2 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.js +217 -38
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
- package/dist/utility/logging/logGenerationCoordinator.js +184 -0
- package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
- package/dist/utility/logging/logRotation.d.ts +46 -0
- package/dist/utility/logging/logRotation.js +365 -0
- package/dist/utility/logging/logRotation.js.map +1 -0
- package/dist/utility/logging/logRotator.d.ts +1 -1
- package/dist/utility/logging/logRotator.js +172 -92
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/npmUtilities.js +6 -4
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/watcherFallback.d.ts +0 -45
- package/dist/utility/watcherFallback.js +1 -125
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.js +6 -3
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +6 -0
- package/json/systemSchema.json +3 -0
- package/npm-shrinkwrap.json +131 -41
- package/package.json +10 -3
- package/resources/DESIGN.md +124 -19
- package/resources/DatabaseTransaction.ts +230 -17
- package/resources/LMDBTransaction.ts +21 -3
- package/resources/PrimaryRocksDatabase.ts +20 -7
- package/resources/RecordEncoder.ts +25 -5
- package/resources/Resource.ts +97 -13
- package/resources/ResourceInterface.ts +8 -0
- package/resources/RocksIndexStore.ts +2 -1
- package/resources/RocksTransactionLogStore.ts +111 -31
- package/resources/Table.ts +1224 -393
- package/resources/analytics/write.ts +10 -3
- package/resources/auditStore.ts +460 -11
- package/resources/dataLoader.ts +3 -4
- package/resources/databases.ts +610 -146
- package/resources/derivedIndexRegistry.ts +56 -0
- package/resources/derivedIndexRuntime.ts +2292 -0
- package/resources/graphql.ts +3 -2
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +905 -46
- package/resources/indexes/hnswDerivedIndex.ts +531 -0
- package/resources/indexes/hnswPlaneBinding.ts +174 -0
- package/resources/nodeIdMapping.ts +50 -0
- package/resources/recordLock.ts +173 -7
- package/resources/recordLockCoordinator.ts +3043 -0
- package/resources/replayLogs.ts +5 -0
- package/resources/replicatedApplyFailure.ts +77 -0
- package/resources/scheduler/scheduler.ts +4 -4
- package/resources/search.ts +169 -49
- package/resources/tracked.ts +73 -22
- package/security/jsLoader.ts +6 -4
- package/server/DESIGN.md +11 -0
- package/server/REST.ts +36 -3
- package/server/http.ts +34 -2
- package/server/serverHelpers/Headers.ts +5 -1
- package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
- package/server/serverHelpers/Request.ts +33 -131
- package/server/serverHelpers/contentTypes.ts +188 -15
- package/server/serverHelpers/serverUtilities.ts +143 -24
- package/server/storageReclamation.ts +2 -2
- package/server/threads/isolatedApplications.ts +157 -0
- package/server/threads/logRotationTransport.ts +40 -0
- package/server/threads/manageThreads.js +254 -12
- package/server/threads/socketRouter.ts +217 -11
- package/server/threads/threadServer.js +30 -7
- package/studio/web/assets/{Chat-BnCBegQz.js → Chat-D3j-1yY1.js} +1 -1
- package/studio/web/assets/{FloatingChat-CoDW1ySS.js → FloatingChat-BxJGYcfB.js} +3 -3
- package/studio/web/assets/{apiToken-Bwk5BLXW.js → apiToken-CT55oWOe.js} +1 -1
- package/studio/web/assets/{applications-DHxGi7JH.js → applications-D9Ct9_vm.js} +1 -1
- package/studio/web/assets/{cssMode-s0cWI-_M.js → cssMode-DV8H7VwA.js} +1 -1
- package/studio/web/assets/{editor-DNcRHK54.js → editor-uatc0unt.js} +1 -1
- package/studio/web/assets/{html-Bdssedlg.js → html-Bm6D6paN.js} +1 -1
- package/studio/web/assets/{htmlMode-CoDlJ3fw.js → htmlMode-CEn7tpLG.js} +1 -1
- package/studio/web/assets/{index-D6sxmFLR.js → index-BIXW6Pu4.js} +5 -5
- package/studio/web/assets/{index.lazy-tmU5BS8s.js → index.lazy-UI7L-Vrk.js} +1 -1
- package/studio/web/assets/{javascript-B8meVSTH.js → javascript-CJ0G3AFZ.js} +1 -1
- package/studio/web/assets/{jsonMode-DpIPd35T.js → jsonMode-DQADAYEa.js} +1 -1
- package/studio/web/assets/{languageServices-C_5FMJzQ.js → languageServices-CAQJXWcI.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-BIzNBzPK.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
- package/studio/web/assets/{notifications-CQf18QKb.js → notifications-BbxTU6Aw.js} +1 -1
- package/studio/web/assets/{notifications-CvZivSbh.js → notifications-Cvb3P1lB.js} +1 -1
- package/studio/web/assets/{profile-DdOwtntb.js → profile-Yyb7gsvL.js} +1 -1
- package/studio/web/assets/{regions-n69fwagr.js → regions-OgjGHlU5.js} +1 -1
- package/studio/web/assets/{register-PfWTCXWB.js → register-6qwNEOY3.js} +2 -2
- package/studio/web/assets/{setComponentFile-Bg6O7X0S.js → setComponentFile-BilDMtgB.js} +1 -1
- package/studio/web/assets/{setup-CUx_aUDl.js → setup-J6qJ7OIU.js} +2 -2
- package/studio/web/assets/{status-D7BVKqX9.js → status-0RWGcfyD.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-DBSyXzMr.js → toggleHighContrast-BIn-vErT.js} +1 -1
- package/studio/web/assets/{tsMode-BByKCjBS.js → tsMode-DgUXku4d.js} +1 -1
- package/studio/web/assets/{typescript-DDLnLpw9.js → typescript-C9orXcsM.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-31CHGaHk.js → useEntityRestURL-BEoXXbUB.js} +1 -1
- package/studio/web/assets/{workers-pR3jRY9D.js → workers-JVzSDmgx.js} +1 -1
- package/studio/web/assets/{xml-2iRnMhQO.js → xml-Cq-S8S4X.js} +1 -1
- package/studio/web/assets/{yaml-Bf92gJpd.js → yaml-sfoRdh1M.js} +1 -1
- package/studio/web/index.html +1 -1
- package/utility/errors/hdbError.ts +54 -0
- package/utility/hdbTerms.ts +2 -0
- package/utility/logging/harper_logger.ts +209 -30
- package/utility/logging/logGenerationCoordinator.ts +196 -0
- package/utility/logging/logRotation.ts +367 -0
- package/utility/logging/logRotator.ts +196 -91
- package/utility/npmUtilities.ts +6 -4
- package/utility/watcherFallback.ts +0 -122
- package/validation/configValidator.ts +6 -3
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Hands the log-rotation coordinator the thread mesh it needs, from this side of the dependency
|
|
4
|
+
// edge: manageThreads already imports harper_logger, so logging can never import manageThreads.
|
|
5
|
+
|
|
6
|
+
import { threadId } from 'node:worker_threads';
|
|
7
|
+
import { setRotationTransport } from '../../utility/logging/logGenerationCoordinator.ts';
|
|
8
|
+
import { broadcast, onMessageByType, onThreadExit } from './manageThreads.js';
|
|
9
|
+
|
|
10
|
+
// Assigned to the `threads` global by manageThreads.
|
|
11
|
+
declare const threads: {
|
|
12
|
+
sendToThread(threadId: number, message: any): boolean;
|
|
13
|
+
[index: number]: { threadId?: number };
|
|
14
|
+
length: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
setRotationTransport({
|
|
18
|
+
threadId,
|
|
19
|
+
broadcast(message) {
|
|
20
|
+
broadcast(message);
|
|
21
|
+
},
|
|
22
|
+
sendToThread(target, message) {
|
|
23
|
+
threads.sendToThread(target, message);
|
|
24
|
+
},
|
|
25
|
+
onMessage(type, handler) {
|
|
26
|
+
onMessageByType(type, handler);
|
|
27
|
+
},
|
|
28
|
+
onThreadExit,
|
|
29
|
+
peerThreadIds() {
|
|
30
|
+
// Job workers included: they hold log descriptors whether or not they take part in ITC gossip,
|
|
31
|
+
// and the deadlock that excludes them from the schema broadcast cannot happen here — the
|
|
32
|
+
// handler only closes a descriptor, and no caller blocks its event loop on the answer.
|
|
33
|
+
const ids = new Set<number>();
|
|
34
|
+
for (let i = 0; i < threads.length; i++) {
|
|
35
|
+
const peer = threads[i].threadId;
|
|
36
|
+
if (peer !== undefined && peer !== threadId) ids.add(peer);
|
|
37
|
+
}
|
|
38
|
+
return ids;
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -64,10 +64,12 @@ let threadTerminationTimeout = process.env.DEV_MODE === 'true' || process.env.DE
|
|
|
64
64
|
const RESTART_TYPE = 'restart';
|
|
65
65
|
const RESTART_PROGRESS_HEARTBEAT_MS = 15000;
|
|
66
66
|
const REQUEST_THREAD_INFO = 'request_thread_info';
|
|
67
|
+
const REQUEST_RUNNING_ISOLATED_APPLICATIONS = 'request-running-isolated-applications';
|
|
67
68
|
const RESOURCE_REPORT = 'resource_report';
|
|
68
69
|
const OS_THREAD_ID = 'os-thread-id';
|
|
69
70
|
const STUCK_WORKER_REPORT = 'stuck-worker-report';
|
|
70
71
|
const THREAD_INFO = 'thread_info';
|
|
72
|
+
const RUNNING_ISOLATED_APPLICATIONS = 'running-isolated-applications';
|
|
71
73
|
const ADDED_PORT = 'added-port';
|
|
72
74
|
const ACKNOWLEDGEMENT = 'ack';
|
|
73
75
|
const REMOVE_PORT = 'remove-port';
|
|
@@ -85,6 +87,7 @@ const AWAIT_PROCESS_GROUP_TERMINATION = 'await-process-group-termination';
|
|
|
85
87
|
const PROCESS_GROUP_TERMINATION_CONFIRMED = 'process-group-termination-confirmed';
|
|
86
88
|
const THREAD_INFO_REQUEST_TIMEOUT_MS = 1000;
|
|
87
89
|
let getThreadInfo;
|
|
90
|
+
let getRunningIsolatedApplications;
|
|
88
91
|
let awaitProcessGroupTermination;
|
|
89
92
|
// Worker-side backstop that force-exits if the graceful shutdown sequence doesn't finish in time.
|
|
90
93
|
let selfExitTimer;
|
|
@@ -151,6 +154,19 @@ module.exports = {
|
|
|
151
154
|
workers,
|
|
152
155
|
setMonitorListener,
|
|
153
156
|
onMessageFromWorkers,
|
|
157
|
+
setIsolatedWorkerReconciler,
|
|
158
|
+
setRunningIsolatedApplicationsGetter,
|
|
159
|
+
isApplicationPrimaryWorker,
|
|
160
|
+
applicationWorkerIndex,
|
|
161
|
+
runsApplicationCodeSingletons,
|
|
162
|
+
isDedicatedWorker,
|
|
163
|
+
markBranchStorePath,
|
|
164
|
+
ownsStoreMaintenance,
|
|
165
|
+
ownsStoreExpiration,
|
|
166
|
+
workersForApplication,
|
|
167
|
+
stopWorker,
|
|
168
|
+
encodeRestartScope,
|
|
169
|
+
decodeRestartScope,
|
|
154
170
|
onMessageByType,
|
|
155
171
|
broadcast,
|
|
156
172
|
broadcastWithAcknowledgement,
|
|
@@ -173,6 +189,11 @@ module.exports = {
|
|
|
173
189
|
isThreadRunning,
|
|
174
190
|
waitUntilConfirmedGone,
|
|
175
191
|
restartNumber: workerData?.restartNumber || 1,
|
|
192
|
+
// Identifies this process incarnation, where the PID cannot: a container reuses PID 1. Minted once
|
|
193
|
+
// on the main thread and carried to workers, so live siblings agree on it — one derived per thread
|
|
194
|
+
// would not. `undefined` on a worker started without it; consumers must fall back, not treat that
|
|
195
|
+
// as a mismatch.
|
|
196
|
+
processIncarnation: workerData ? workerData.processIncarnation : randomBytes(8).toString('hex'),
|
|
176
197
|
};
|
|
177
198
|
|
|
178
199
|
connectedPorts.onMessageByType = onMessageByType;
|
|
@@ -191,6 +212,9 @@ connectedPorts.sendToThread = function (threadId, message) {
|
|
|
191
212
|
throw err;
|
|
192
213
|
}
|
|
193
214
|
};
|
|
215
|
+
// Direct thread-to-thread send, so a worker can reach a sibling (e.g. the record lock owner worker)
|
|
216
|
+
// without a hop through main. Returns false when no port for the thread is connected.
|
|
217
|
+
module.exports.sendToThread = connectedPorts.sendToThread;
|
|
194
218
|
module.exports.whenThreadsStarted = new Promise((resolve) => {
|
|
195
219
|
module.exports.threadsHaveStarted = resolve;
|
|
196
220
|
});
|
|
@@ -206,6 +230,101 @@ function setTerminateTimeout(newTimeout) {
|
|
|
206
230
|
function getWorkerIndex() {
|
|
207
231
|
return workerData ? workerData.workerIndex : isMainWorker ? 0 : undefined;
|
|
208
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* The worker that owns `applicationName`'s per-application singletons (its scheduled jobs, its data
|
|
235
|
+
* files): pool worker 0 for a shared application and for root-level plugins (which pass no name), the
|
|
236
|
+
* dedicated worker for an isolated one -- never index 0, so node-wide duties stay on the pool, and
|
|
237
|
+
* never a dedicated worker for anything but its own application.
|
|
238
|
+
*/
|
|
239
|
+
function isApplicationPrimaryWorker(applicationName) {
|
|
240
|
+
if (workerData?.isolatedApplication !== undefined) return applicationName === workerData.isolatedApplication;
|
|
241
|
+
return getWorkerIndex() === 0;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Stores that exist only on this thread: the branch stores an isolated application opened in its
|
|
245
|
+
* dedicated worker. Registered by openBranchDatabase, so the ownership predicates below can tell them
|
|
246
|
+
* from the shared stores every thread has open.
|
|
247
|
+
*/
|
|
248
|
+
const branchStorePaths = new Set();
|
|
249
|
+
function markBranchStorePath(path, isBranch = true) {
|
|
250
|
+
if (isBranch) branchStorePaths.add(path);
|
|
251
|
+
else branchStorePaths.delete(path);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Whether this thread runs the "last worker" per-store maintenance for `storePath` (TTL scans, storage
|
|
255
|
+
* reclamation, audit cleanup). Shared stores belong to the last pool worker; a dedicated worker
|
|
256
|
+
* maintains only its own branch stores, which no other thread has open.
|
|
257
|
+
*/
|
|
258
|
+
function ownsStoreMaintenance(storePath) {
|
|
259
|
+
if (workerData?.isolatedApplication !== undefined) return branchStorePaths.has(storePath);
|
|
260
|
+
return getWorkerIndex() === getWorkerCount() - 1;
|
|
261
|
+
}
|
|
262
|
+
/** The "worker 0" counterpart: expiration eviction for `storePath`. */
|
|
263
|
+
function ownsStoreExpiration(storePath) {
|
|
264
|
+
if (workerData?.isolatedApplication !== undefined) return branchStorePaths.has(storePath);
|
|
265
|
+
return getWorkerIndex() === 0;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Whether a singleton set up by APPLICATION CODE runs here (a caching table's `sourcedFrom`
|
|
269
|
+
* subscription): pool worker 0, or a dedicated worker -- the only code that runs on one is its own
|
|
270
|
+
* application's, so whatever it sets up is that application's to run. Not for root-level plugins,
|
|
271
|
+
* which load on every thread and must use isApplicationPrimaryWorker(name).
|
|
272
|
+
*/
|
|
273
|
+
function runsApplicationCodeSingletons() {
|
|
274
|
+
return getWorkerIndex() === 0 || workerData?.isolatedApplication !== undefined;
|
|
275
|
+
}
|
|
276
|
+
/** Whether this thread is a worker dedicated to one isolated application. */
|
|
277
|
+
function isDedicatedWorker() {
|
|
278
|
+
return workerData?.isolatedApplication !== undefined;
|
|
279
|
+
}
|
|
280
|
+
/** The worker index as the application sees it: a dedicated worker is its application's worker 0. */
|
|
281
|
+
function applicationWorkerIndex() {
|
|
282
|
+
return workerData?.isolatedApplication !== undefined ? 0 : getWorkerIndex();
|
|
283
|
+
}
|
|
284
|
+
/** Every started worker dedicated to `application`, including a replacement still booting. */
|
|
285
|
+
function workersForApplication(application) {
|
|
286
|
+
return workers.filter((worker) => worker.application === application);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Stop one worker for good: shut it down, honour the drain extension it may ask for, force it after
|
|
290
|
+
* the same backstop the rolling restart uses (FORCE_EXIT on Bun, where terminate() segfaults), and
|
|
291
|
+
* resolve once it has exited. Marked as shut down first so its exit does not start a replacement.
|
|
292
|
+
*/
|
|
293
|
+
function stopWorker(worker) {
|
|
294
|
+
worker.wasShutdown = true;
|
|
295
|
+
return new Promise((resolve) => {
|
|
296
|
+
const armTerminate = (delay) =>
|
|
297
|
+
setTimeout(() => {
|
|
298
|
+
harperLogger.warn('Thread did not voluntarily terminate, terminating from the outside', worker.threadId);
|
|
299
|
+
if (isBun) {
|
|
300
|
+
try {
|
|
301
|
+
worker.postMessage({ type: FORCE_EXIT });
|
|
302
|
+
} catch {}
|
|
303
|
+
} else {
|
|
304
|
+
worker.terminate();
|
|
305
|
+
}
|
|
306
|
+
}, delay).unref();
|
|
307
|
+
let timeout = armTerminate(threadTerminationTimeout * 2);
|
|
308
|
+
worker.extendTerminateDeadline = (deadlineMs) => {
|
|
309
|
+
clearTimeout(timeout);
|
|
310
|
+
const { boundedTerminateDelay, getShutdownDrainCeilingMs } = require('../../components/shutdownDrain.ts');
|
|
311
|
+
timeout = armTerminate(
|
|
312
|
+
boundedTerminateDelay(deadlineMs, Date.now(), threadTerminationTimeout * 2, getShutdownDrainCeilingMs())
|
|
313
|
+
);
|
|
314
|
+
};
|
|
315
|
+
worker.on('exit', () => {
|
|
316
|
+
clearTimeout(timeout);
|
|
317
|
+
worker.extendTerminateDeadline = undefined;
|
|
318
|
+
resolve();
|
|
319
|
+
});
|
|
320
|
+
try {
|
|
321
|
+
worker.postMessage({ restartNumber: module.exports.restartNumber, type: hdbTerms.ITC_EVENT_TYPES.SHUTDOWN });
|
|
322
|
+
} catch {
|
|
323
|
+
clearTimeout(timeout);
|
|
324
|
+
resolve(); // already gone
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
209
328
|
function getWorkerCount() {
|
|
210
329
|
return workerData ? workerData.workerCount : isMainWorker ? 1 : undefined;
|
|
211
330
|
}
|
|
@@ -239,8 +358,10 @@ const RESERVED_WORKER_DATA_KEYS = [
|
|
|
239
358
|
'workerCount',
|
|
240
359
|
'name',
|
|
241
360
|
'restartNumber',
|
|
361
|
+
'processIncarnation',
|
|
242
362
|
'ticketKeys',
|
|
243
363
|
'noServerStart',
|
|
364
|
+
'isolatedApplication',
|
|
244
365
|
'__proto__', // never a legitimate payload name; spread would define it as an own property
|
|
245
366
|
];
|
|
246
367
|
const workerDataProviders = new Map();
|
|
@@ -294,20 +415,31 @@ function getTicketKeys() {
|
|
|
294
415
|
ticketKeys = isMainThread ? randomBytes(48) : workerData.ticketKeys;
|
|
295
416
|
return ticketKeys;
|
|
296
417
|
}
|
|
418
|
+
// What application code sees: a dedicated worker is its application's only worker, index 0 of 1, so
|
|
419
|
+
// the documented partitioning idiom (`hash % server.workerCount === server.workerIndex`) covers
|
|
420
|
+
// everything there. Node-wide duties keep using the raw getWorkerIndex/getWorkerCount.
|
|
297
421
|
Object.defineProperty(server, 'workerIndex', {
|
|
298
422
|
get() {
|
|
299
|
-
return
|
|
423
|
+
return applicationWorkerIndex();
|
|
300
424
|
},
|
|
301
425
|
});
|
|
302
426
|
Object.defineProperty(server, 'workerCount', {
|
|
303
427
|
get() {
|
|
304
|
-
return getWorkerCount();
|
|
428
|
+
return workerData?.isolatedApplication !== undefined ? 1 : getWorkerCount();
|
|
305
429
|
},
|
|
306
430
|
});
|
|
307
431
|
if (!parentPort) {
|
|
308
432
|
onMessageByType(REQUEST_THREAD_INFO, (message, worker) => {
|
|
309
433
|
if (worker) sendThreadInfo(worker);
|
|
310
434
|
});
|
|
435
|
+
onMessageByType(REQUEST_RUNNING_ISOLATED_APPLICATIONS, (message, worker) => {
|
|
436
|
+
if (worker)
|
|
437
|
+
worker.postMessage({
|
|
438
|
+
type: RUNNING_ISOLATED_APPLICATIONS,
|
|
439
|
+
requestId: message.requestId,
|
|
440
|
+
applications: runningIsolatedApplicationsGetter(),
|
|
441
|
+
});
|
|
442
|
+
});
|
|
311
443
|
onMessageByType(RESOURCE_REPORT, (message, worker) => {
|
|
312
444
|
if (worker) recordResourceReport(worker, message);
|
|
313
445
|
});
|
|
@@ -342,11 +474,12 @@ listenersByType.set(hdbTerms.ITC_EVENT_TYPES.MIDDLEWARE_CHAINS_RESPONSE, null);
|
|
|
342
474
|
listenersByType.set(hdbTerms.ITC_EVENT_TYPES.OPERATION_REGISTERED, null);
|
|
343
475
|
listenersByType.set(hdbTerms.ITC_EVENT_TYPES.OPERATION_EXECUTE_REQUEST, null);
|
|
344
476
|
listenersByType.set(hdbTerms.ITC_EVENT_TYPES.OPERATION_EXECUTE_RESPONSE, null);
|
|
345
|
-
//
|
|
477
|
+
// These request/response functions register their own one-shot parentPort listener per
|
|
346
478
|
// call rather than going through onMessageByType, so without this, every reply would also reach
|
|
347
479
|
// addPort's permanent dispatcher as an "unregistered" type: notifyMessageListeners would warn and
|
|
348
480
|
// queue each one in messagesQueuedByType forever, and a lock-wait polls every 50ms.
|
|
349
481
|
listenersByType.set(THREAD_INFO, null);
|
|
482
|
+
listenersByType.set(RUNNING_ISOLATED_APPLICATIONS, null);
|
|
350
483
|
listenersByType.set(PROCESS_GROUP_TERMINATION_CONFIRMED, null);
|
|
351
484
|
|
|
352
485
|
function startWorker(path, options = {}) {
|
|
@@ -370,7 +503,7 @@ function startWorker(path, options = {}) {
|
|
|
370
503
|
availableMemory = Math.min(availableMemory, totalmem(), 20000 * MB);
|
|
371
504
|
const maxOldMemory =
|
|
372
505
|
resolveThreadHeapMemoryMb(envMgr.get(hdbTerms.CONFIG_PARAMS.THREADS_MAXHEAPMEMORY)) ??
|
|
373
|
-
Math.max(Math.floor(availableMemory / MB / (10 + (options.threadCount || 1) / 4)), 512);
|
|
506
|
+
Math.max(Math.floor(availableMemory / MB / (10 + (options.heapShareCount || options.threadCount || 1) / 4)), 512);
|
|
374
507
|
// Max young memory space (semi-space for scavenger) is 1/128 of max memory (limited to 16-64). For most of our m5
|
|
375
508
|
// machines this will be 64MB (less for t3's). This is based on recommendations from:
|
|
376
509
|
// https://www.alibabacloud.com/blog/node-js-application-troubleshooting-manual---comprehensive-gc-problems-and-optimization594965
|
|
@@ -416,6 +549,9 @@ function startWorker(path, options = {}) {
|
|
|
416
549
|
for (const requirePath of getRequireModules()) execArgv.push('--require', requirePath);
|
|
417
550
|
}
|
|
418
551
|
|
|
552
|
+
// Only a start that declares the serving topology may write it; see DESIGN.md on the two workerCounts.
|
|
553
|
+
if (typeof options.threadCount === 'number') workerCount = options.threadCount;
|
|
554
|
+
|
|
419
555
|
const worker = new Worker(isAbsolute(path) ? path : join(PACKAGE_ROOT, path), {
|
|
420
556
|
resourceLimits: {
|
|
421
557
|
maxOldGenerationSizeMb: maxOldMemory,
|
|
@@ -430,9 +566,11 @@ function startWorker(path, options = {}) {
|
|
|
430
566
|
addThreadIds: channelsToConnect.map((channel) => channel.existingPort.threadId),
|
|
431
567
|
addPortIsJobWorkers: channelsToConnect.map((channel) => channel.existingPort.isJobWorker === true),
|
|
432
568
|
workerIndex: options.workerIndex,
|
|
433
|
-
workerCount:
|
|
569
|
+
workerCount: options.threadCount,
|
|
434
570
|
name: options.name,
|
|
571
|
+
isolatedApplication: options.application,
|
|
435
572
|
restartNumber: module.exports.restartNumber,
|
|
573
|
+
processIncarnation: module.exports.processIncarnation,
|
|
436
574
|
ticketKeys: getTicketKeys(),
|
|
437
575
|
},
|
|
438
576
|
transferList: portsToSend,
|
|
@@ -466,7 +604,12 @@ function startWorker(path, options = {}) {
|
|
|
466
604
|
});
|
|
467
605
|
worker.on('exit', (_code) => {
|
|
468
606
|
workers.splice(workers.indexOf(worker), 1);
|
|
469
|
-
if (
|
|
607
|
+
if (
|
|
608
|
+
!processShuttingDown &&
|
|
609
|
+
!worker.wasShutdown &&
|
|
610
|
+
options.autoRestart !== false &&
|
|
611
|
+
options.shouldAutoRestart?.(worker) !== false
|
|
612
|
+
) {
|
|
470
613
|
// if this wasn't an intentional shutdown, restart now (unless we have tried too many times)
|
|
471
614
|
if (worker.unexpectedRestarts < MAX_UNEXPECTED_RESTARTS) {
|
|
472
615
|
options.unexpectedRestarts = worker.unexpectedRestarts + 1;
|
|
@@ -481,6 +624,7 @@ function startWorker(path, options = {}) {
|
|
|
481
624
|
startMonitoring();
|
|
482
625
|
if (options.onStarted) options.onStarted(worker); // notify that it is ready
|
|
483
626
|
worker.name = options.name;
|
|
627
|
+
worker.application = options.application; // the isolated application this worker is dedicated to, if any
|
|
484
628
|
return worker;
|
|
485
629
|
}
|
|
486
630
|
|
|
@@ -502,12 +646,19 @@ const OVERLAPPING_RESTART_TYPES = [hdbTerms.THREAD_TYPES.HTTP];
|
|
|
502
646
|
* from a worker, nothing — the restart is handed to the main thread.
|
|
503
647
|
*/
|
|
504
648
|
|
|
649
|
+
/**
|
|
650
|
+
* `application` selects which workers of the type restart: omitted preserves the historic all-worker
|
|
651
|
+
* behavior, explicit undefined restarts the shared pool only, a name restarts only that application's
|
|
652
|
+
* dedicated worker, and '*' restarts all.
|
|
653
|
+
*/
|
|
505
654
|
async function restartWorkers(
|
|
506
655
|
name = null,
|
|
507
656
|
maxWorkersDown = Math.max(Math.floor(workerCount / 8), 1), // restart 1/8 of the threads at a time, but at least 1
|
|
508
657
|
startReplacementThreads = true,
|
|
509
|
-
onProgress = null
|
|
658
|
+
onProgress = null,
|
|
659
|
+
application = undefined
|
|
510
660
|
) {
|
|
661
|
+
if (arguments.length < 5) application = '*';
|
|
511
662
|
if (isMainThread) {
|
|
512
663
|
// Declining is not the same as delegating: a caller reporting on the restart must not read this
|
|
513
664
|
// as "another thread is completing it".
|
|
@@ -520,9 +671,19 @@ async function restartWorkers(
|
|
|
520
671
|
} catch (e) {
|
|
521
672
|
harperLogger.error('Unable to reestablish current working directory', e);
|
|
522
673
|
}
|
|
674
|
+
const freshlyStarted = new Set(); // dedicated workers the reconcile just started: already on the new code
|
|
523
675
|
// problematic cyclic dependency, bind late
|
|
524
676
|
const { resetRestartNeeded } = require('../../components/requestRestart.ts');
|
|
525
|
-
|
|
677
|
+
// One process-wide bit cannot say WHICH application is pending, so it may only be cleared by a
|
|
678
|
+
// restart that demonstrably covers every worker the bit could stand for. A restart scoped to one
|
|
679
|
+
// application leaves the whole pool on its old code; a pool restart replaces every pool worker and
|
|
680
|
+
// reconciles dedicated slots, but leaves an already-running dedicated worker on its old modules.
|
|
681
|
+
// Clearing from either would report restartRequired: false while a deployed component is still
|
|
682
|
+
// loaded nowhere. So: all workers always, the pool only while no dedicated worker is running --
|
|
683
|
+
// which is every node that uses no isolated application, i.e. the historic behavior unchanged.
|
|
684
|
+
const coversEveryWorker =
|
|
685
|
+
application === '*' || (application === undefined && !workers.some((worker) => worker.application));
|
|
686
|
+
if (coversEveryWorker) resetRestartNeeded();
|
|
526
687
|
// This is here to prevent circular dependencies
|
|
527
688
|
if (startReplacementThreads) {
|
|
528
689
|
const { loadRootComponents } = require('../loadRootComponents.js');
|
|
@@ -532,6 +693,13 @@ async function restartWorkers(
|
|
|
532
693
|
const loading = setInterval(() => onProgress?.(), RESTART_PROGRESS_HEARTBEAT_MS).unref();
|
|
533
694
|
try {
|
|
534
695
|
await loadRootComponents();
|
|
696
|
+
// isolated applications added or removed by the reload get their dedicated worker started or
|
|
697
|
+
// stopped; a crash-looping newcomer can take a while, so the heartbeat runs through this too
|
|
698
|
+
try {
|
|
699
|
+
for (const application of (await isolatedWorkerReconciler?.()) ?? []) freshlyStarted.add(application);
|
|
700
|
+
} catch (error) {
|
|
701
|
+
harperLogger.error('Could not reconcile isolated application workers', error);
|
|
702
|
+
}
|
|
535
703
|
} finally {
|
|
536
704
|
clearInterval(loading);
|
|
537
705
|
}
|
|
@@ -539,7 +707,10 @@ async function restartWorkers(
|
|
|
539
707
|
}
|
|
540
708
|
|
|
541
709
|
module.exports.restartNumber++;
|
|
542
|
-
|
|
710
|
+
// `Infinity` is shutdownWorkers' "all at once" sentinel and must survive.
|
|
711
|
+
if (typeof maxWorkersDown !== 'number' || Number.isNaN(maxWorkersDown)) {
|
|
712
|
+
maxWorkersDown = 1;
|
|
713
|
+
} else if (maxWorkersDown < 1) {
|
|
543
714
|
// we accept a ratio of workers, and compute absolute maximum being down at a time from the total number of
|
|
544
715
|
// threads
|
|
545
716
|
maxWorkersDown = maxWorkersDown * workers.length;
|
|
@@ -566,14 +737,17 @@ async function restartWorkers(
|
|
|
566
737
|
// replacement — an unavoidable brief gap, but only for worker-owned listeners, since the main
|
|
567
738
|
// thread keeps serving the HTTP ports throughout. This ordering is also what lets
|
|
568
739
|
// listenOnPorts() treat a dedicated listener's EADDRINUSE as an external conflict.
|
|
569
|
-
const
|
|
740
|
+
const platformCanPreStartReplacement = process.platform !== 'win32' && process.platform !== 'darwin' && !isBun;
|
|
570
741
|
const restarting = workers.slice(0);
|
|
571
742
|
for (let index = 0; index < restarting.length; index++) {
|
|
572
743
|
const worker = restarting[index];
|
|
573
744
|
// Terminal shutdown: stop replacing workers mid-loop — the guard for every replacement start below.
|
|
574
745
|
if (processShuttingDown && startReplacementThreads) break;
|
|
575
746
|
if ((name && worker.name !== name) || worker.wasShutdown) continue; // filter by type, if specified
|
|
747
|
+
if (application !== '*' && worker.application !== application) continue; // and by isolated application
|
|
748
|
+
if (worker.application && freshlyStarted.has(worker.application)) continue;
|
|
576
749
|
const overlapping = OVERLAPPING_RESTART_TYPES.indexOf(worker.name) > -1;
|
|
750
|
+
const canPreStartReplacement = platformCanPreStartReplacement && !worker.application;
|
|
577
751
|
if (overlapping && startReplacementThreads && canPreStartReplacement) {
|
|
578
752
|
// Overlapping restart: start the replacement and wait until it is accepting connections
|
|
579
753
|
// *before* shutting down the worker it replaces. The replacement joins the (SO_REUSEPORT)
|
|
@@ -754,6 +928,7 @@ async function restartWorkers(
|
|
|
754
928
|
parentPort.postMessage({
|
|
755
929
|
type: RESTART_TYPE,
|
|
756
930
|
workerType: name,
|
|
931
|
+
scope: encodeRestartScope(application),
|
|
757
932
|
});
|
|
758
933
|
}
|
|
759
934
|
}
|
|
@@ -803,7 +978,7 @@ function whenWorkerStarted(newWorker) {
|
|
|
803
978
|
});
|
|
804
979
|
}
|
|
805
980
|
function shutdownWorkers(name) {
|
|
806
|
-
return restartWorkers(name, Infinity, false);
|
|
981
|
+
return restartWorkers(name, Infinity, false, null, '*');
|
|
807
982
|
}
|
|
808
983
|
function beginProcessShutdown() {
|
|
809
984
|
processShuttingDown = true;
|
|
@@ -823,6 +998,28 @@ async function shutdownWorkersNow(name) {
|
|
|
823
998
|
}
|
|
824
999
|
}
|
|
825
1000
|
|
|
1001
|
+
/**
|
|
1002
|
+
* The restart scope on the wire: a worker cannot post `undefined` and have it mean "the pool" (a
|
|
1003
|
+
* message with no scope at all means "everything", as every pre-existing sender intends).
|
|
1004
|
+
*/
|
|
1005
|
+
function encodeRestartScope(application) {
|
|
1006
|
+
return application === undefined ? '' : application; // '' is not a legal application name
|
|
1007
|
+
}
|
|
1008
|
+
function decodeRestartScope(message) {
|
|
1009
|
+
if (message.scope === undefined) return '*';
|
|
1010
|
+
return message.scope === '' ? undefined : message.scope;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
let isolatedWorkerReconciler = null;
|
|
1014
|
+
let runningIsolatedApplicationsGetter = () => [];
|
|
1015
|
+
/** Registered by socketRouter: starts and stops dedicated workers to match the root config's isolated applications. */
|
|
1016
|
+
function setIsolatedWorkerReconciler(reconcile) {
|
|
1017
|
+
isolatedWorkerReconciler = reconcile;
|
|
1018
|
+
}
|
|
1019
|
+
function setRunningIsolatedApplicationsGetter(getter) {
|
|
1020
|
+
runningIsolatedApplicationsGetter = getter;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
826
1023
|
const messageListeners = [];
|
|
827
1024
|
function onMessageFromWorkers(listener) {
|
|
828
1025
|
messageListeners.push(listener);
|
|
@@ -1089,6 +1286,7 @@ function getChildWorkerInfo() {
|
|
|
1089
1286
|
return workers.map((worker) => ({
|
|
1090
1287
|
threadId: worker.threadId,
|
|
1091
1288
|
name: worker.name,
|
|
1289
|
+
application: worker.application,
|
|
1092
1290
|
heapTotal: worker.resources?.heapTotal,
|
|
1093
1291
|
heapUsed: worker.resources?.heapUsed,
|
|
1094
1292
|
externalMemory: worker.resources?.external,
|
|
@@ -1198,6 +1396,38 @@ if (parentPort && workerData?.addPorts) {
|
|
|
1198
1396
|
}, timeoutMs);
|
|
1199
1397
|
}
|
|
1200
1398
|
});
|
|
1399
|
+
let nextRunningIsolatedApplicationsRequestId = 0;
|
|
1400
|
+
getRunningIsolatedApplications = (timeoutMs) =>
|
|
1401
|
+
new Promise((resolve, reject) => {
|
|
1402
|
+
const requestId = ++nextRunningIsolatedApplicationsRequestId;
|
|
1403
|
+
let timeout;
|
|
1404
|
+
parentPort.on('message', receiveApplications);
|
|
1405
|
+
try {
|
|
1406
|
+
parentPort.postMessage({ type: REQUEST_RUNNING_ISOLATED_APPLICATIONS, requestId });
|
|
1407
|
+
} catch (error) {
|
|
1408
|
+
cleanup();
|
|
1409
|
+
reject(error);
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
function receiveApplications(message) {
|
|
1413
|
+
if (message.type === RUNNING_ISOLATED_APPLICATIONS && message.requestId === requestId) {
|
|
1414
|
+
cleanup();
|
|
1415
|
+
resolve(message.applications);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
function cleanup() {
|
|
1419
|
+
if (timeout) clearTimeout(timeout);
|
|
1420
|
+
parentPort.off('message', receiveApplications);
|
|
1421
|
+
}
|
|
1422
|
+
if (timeoutMs != null) {
|
|
1423
|
+
timeout = setTimeout(() => {
|
|
1424
|
+
cleanup();
|
|
1425
|
+
const error = new Error(`Timed out waiting for isolated application topology after ${timeoutMs}ms`);
|
|
1426
|
+
error.code = 'ERR_ISOLATED_APPLICATIONS_TIMEOUT';
|
|
1427
|
+
reject(error);
|
|
1428
|
+
}, timeoutMs);
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1201
1431
|
let awaitTerminationRequestId = 0;
|
|
1202
1432
|
awaitProcessGroupTermination = (ownerThreadId, signal) =>
|
|
1203
1433
|
new Promise((resolve) => {
|
|
@@ -1222,10 +1452,18 @@ if (parentPort && workerData?.addPorts) {
|
|
|
1222
1452
|
});
|
|
1223
1453
|
} else {
|
|
1224
1454
|
getThreadInfo = getChildWorkerInfo;
|
|
1455
|
+
getRunningIsolatedApplications = isMainThread
|
|
1456
|
+
? () => runningIsolatedApplicationsGetter()
|
|
1457
|
+
: () => {
|
|
1458
|
+
const error = new Error('No channel to the main thread for isolated application topology');
|
|
1459
|
+
error.code = 'ERR_ISOLATED_APPLICATIONS_UNAVAILABLE';
|
|
1460
|
+
return Promise.reject(error);
|
|
1461
|
+
};
|
|
1225
1462
|
awaitProcessGroupTermination = (ownerThreadId) =>
|
|
1226
1463
|
pendingProcessGroupTerminations.get(ownerThreadId) ?? Promise.resolve();
|
|
1227
1464
|
}
|
|
1228
1465
|
module.exports.getThreadInfo = getThreadInfo;
|
|
1466
|
+
module.exports.getRunningIsolatedApplications = getRunningIsolatedApplications;
|
|
1229
1467
|
|
|
1230
1468
|
// Listeners notified when a connected thread's port closes (worker exit/restart), so
|
|
1231
1469
|
// modules holding per-thread state (e.g. registeredOperations' registry and in-flight
|
|
@@ -1720,7 +1958,7 @@ if (isMainThread) {
|
|
|
1720
1958
|
if (queuedRestart) clearTimeout(queuedRestart);
|
|
1721
1959
|
queuedRestart = setTimeout(async () => {
|
|
1722
1960
|
if (beforeRestart) await beforeRestart();
|
|
1723
|
-
await restartWorkers();
|
|
1961
|
+
await restartWorkers(undefined, undefined, true, null, '*');
|
|
1724
1962
|
console.log('Reloaded Harper components, changed files:', Array.from(changedFiles));
|
|
1725
1963
|
changedFiles.clear();
|
|
1726
1964
|
}, 100);
|
|
@@ -1742,3 +1980,7 @@ if (isMainThread) {
|
|
|
1742
1980
|
realExit(0);
|
|
1743
1981
|
});
|
|
1744
1982
|
}
|
|
1983
|
+
|
|
1984
|
+
// Required here, not from logging, which must never import this module; last in the file because it
|
|
1985
|
+
// calls onThreadExit.
|
|
1986
|
+
require('./logRotationTransport.ts');
|