velocious 1.0.631 → 1.0.633
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -5
- package/build/application.js +30 -10
- package/build/background-jobs/forked-runner-child.js +26 -30
- package/build/background-jobs/job-runner.js +5 -7
- package/build/background-jobs/lifecycle-client.js +3 -3
- package/build/background-jobs/local-dispatcher.js +29 -18
- package/build/background-jobs/main.js +33 -28
- package/build/background-jobs/pooled-runner-child.js +17 -9
- package/build/background-jobs/runner-graceful-shutdown.js +26 -10
- package/build/background-jobs/worker.js +34 -13
- package/build/configuration-types.js +8 -0
- package/build/configuration.js +267 -32
- package/build/database/drivers/base.js +163 -119
- package/build/database/drivers/sqlite/index.web.js +19 -11
- package/build/database/migrator.js +8 -5
- package/build/database/pool/async-tracked-multi-connection.js +73 -24
- package/build/database/pool/base.js +5 -0
- package/build/database/pool/single-multi-use.js +43 -11
- package/build/database/record/attachments/store.js +35 -26
- package/build/environment-handlers/base.js +122 -9
- package/build/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -16
- package/build/environment-handlers/node/cli/commands/server.js +7 -2
- package/build/environment-handlers/node.js +15 -9
- package/build/error-reporting/request-details.js +28 -31
- package/build/frontend-model-controller.js +19 -13
- package/build/http-server/client/index.js +5 -13
- package/build/http-server/client/request-runner.js +26 -9
- package/build/http-server/client/request-timing.js +19 -0
- package/build/http-server/client/websocket-session.js +54 -14
- package/build/http-server/websocket-events-host.js +10 -8
- package/build/http-server/worker-handler/worker-thread.js +13 -6
- package/build/initializer.js +19 -1
- package/build/log-redactor.js +341 -0
- package/build/routes/resolver.js +32 -4
- package/build/src/application.d.ts +7 -0
- package/build/src/application.d.ts.map +1 -1
- package/build/src/application.js +32 -12
- package/build/src/background-jobs/forked-runner-child.js +25 -31
- package/build/src/background-jobs/job-runner.d.ts +3 -1
- package/build/src/background-jobs/job-runner.d.ts.map +1 -1
- package/build/src/background-jobs/job-runner.js +6 -9
- package/build/src/background-jobs/lifecycle-client.d.ts +1 -0
- package/build/src/background-jobs/lifecycle-client.d.ts.map +1 -1
- package/build/src/background-jobs/lifecycle-client.js +4 -4
- package/build/src/background-jobs/local-dispatcher.d.ts.map +1 -1
- package/build/src/background-jobs/local-dispatcher.js +31 -20
- package/build/src/background-jobs/main.d.ts +0 -4
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +34 -32
- package/build/src/background-jobs/pooled-runner-child.js +18 -11
- package/build/src/background-jobs/runner-graceful-shutdown.d.ts +9 -0
- package/build/src/background-jobs/runner-graceful-shutdown.d.ts.map +1 -1
- package/build/src/background-jobs/runner-graceful-shutdown.js +27 -13
- package/build/src/background-jobs/worker.d.ts +5 -0
- package/build/src/background-jobs/worker.d.ts.map +1 -1
- package/build/src/background-jobs/worker.js +31 -18
- package/build/src/configuration-types.d.ts +21 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +8 -1
- package/build/src/configuration.d.ts +94 -0
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +239 -31
- package/build/src/database/drivers/base.d.ts +5 -1
- package/build/src/database/drivers/base.d.ts.map +1 -1
- package/build/src/database/drivers/base.js +159 -115
- package/build/src/database/drivers/sqlite/index.web.d.ts +2 -0
- package/build/src/database/drivers/sqlite/index.web.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.web.js +17 -11
- package/build/src/database/migrator.d.ts.map +1 -1
- package/build/src/database/migrator.js +9 -6
- package/build/src/database/pool/async-tracked-multi-connection.d.ts +15 -0
- package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
- package/build/src/database/pool/async-tracked-multi-connection.js +71 -21
- package/build/src/database/pool/base.d.ts +2 -0
- package/build/src/database/pool/base.d.ts.map +1 -1
- package/build/src/database/pool/base.js +5 -1
- package/build/src/database/pool/single-multi-use.d.ts.map +1 -1
- package/build/src/database/pool/single-multi-use.js +47 -13
- package/build/src/database/record/attachments/store.d.ts +6 -0
- package/build/src/database/record/attachments/store.d.ts.map +1 -1
- package/build/src/database/record/attachments/store.js +31 -23
- package/build/src/environment-handlers/base.d.ts +79 -8
- package/build/src/environment-handlers/base.d.ts.map +1 -1
- package/build/src/environment-handlers/base.js +106 -10
- package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.d.ts +36 -0
- package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/background-jobs-worker.js +45 -16
- package/build/src/environment-handlers/node/cli/commands/server.d.ts.map +1 -1
- package/build/src/environment-handlers/node/cli/commands/server.js +8 -3
- package/build/src/environment-handlers/node.d.ts +3 -6
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +13 -10
- package/build/src/error-reporting/request-details.d.ts +8 -1
- package/build/src/error-reporting/request-details.d.ts.map +1 -1
- package/build/src/error-reporting/request-details.js +30 -32
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +20 -14
- package/build/src/http-server/client/index.d.ts.map +1 -1
- package/build/src/http-server/client/index.js +5 -12
- package/build/src/http-server/client/request-runner.d.ts.map +1 -1
- package/build/src/http-server/client/request-runner.js +23 -10
- package/build/src/http-server/client/request-timing.d.ts +13 -0
- package/build/src/http-server/client/request-timing.d.ts.map +1 -1
- package/build/src/http-server/client/request-timing.js +19 -1
- package/build/src/http-server/client/websocket-session.d.ts +9 -2
- package/build/src/http-server/client/websocket-session.d.ts.map +1 -1
- package/build/src/http-server/client/websocket-session.js +46 -15
- package/build/src/http-server/websocket-events-host.d.ts.map +1 -1
- package/build/src/http-server/websocket-events-host.js +11 -8
- package/build/src/http-server/worker-handler/worker-thread.d.ts.map +1 -1
- package/build/src/http-server/worker-handler/worker-thread.js +13 -6
- package/build/src/initializer.d.ts +14 -1
- package/build/src/initializer.d.ts.map +1 -1
- package/build/src/initializer.js +18 -2
- package/build/src/log-redactor.d.ts +97 -0
- package/build/src/log-redactor.d.ts.map +1 -0
- package/build/src/log-redactor.js +297 -0
- package/build/src/routes/resolver.d.ts +7 -0
- package/build/src/routes/resolver.d.ts.map +1 -1
- package/build/src/routes/resolver.js +26 -5
- package/build/src/testing/sqljs-test-database.d.ts +41 -0
- package/build/src/testing/sqljs-test-database.d.ts.map +1 -0
- package/build/src/testing/sqljs-test-database.js +72 -0
- package/build/src/testing/test-runner.d.ts +79 -6
- package/build/src/testing/test-runner.d.ts.map +1 -1
- package/build/src/testing/test-runner.js +498 -139
- package/build/src/testing/test.js +2 -2
- package/build/src/utils/shutdown-lifecycle.d.ts +13 -0
- package/build/src/utils/shutdown-lifecycle.d.ts.map +1 -1
- package/build/src/utils/shutdown-lifecycle.js +35 -26
- package/build/testing/sqljs-test-database.js +73 -0
- package/build/testing/test-runner.js +529 -141
- package/build/testing/test.js +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/utils/shutdown-lifecycle.js +33 -30
- package/package.json +1 -1
- package/scripts/test-browser.js +16 -29
- package/src/application.js +30 -10
- package/src/background-jobs/forked-runner-child.js +26 -30
- package/src/background-jobs/job-runner.js +5 -7
- package/src/background-jobs/lifecycle-client.js +3 -3
- package/src/background-jobs/local-dispatcher.js +29 -18
- package/src/background-jobs/main.js +33 -28
- package/src/background-jobs/pooled-runner-child.js +17 -9
- package/src/background-jobs/runner-graceful-shutdown.js +26 -10
- package/src/background-jobs/worker.js +34 -13
- package/src/configuration-types.js +8 -0
- package/src/configuration.js +267 -32
- package/src/database/drivers/base.js +163 -119
- package/src/database/drivers/sqlite/index.web.js +19 -11
- package/src/database/migrator.js +8 -5
- package/src/database/pool/async-tracked-multi-connection.js +73 -24
- package/src/database/pool/base.js +5 -0
- package/src/database/pool/single-multi-use.js +43 -11
- package/src/database/record/attachments/store.js +35 -26
- package/src/environment-handlers/base.js +122 -9
- package/src/environment-handlers/node/cli/commands/background-jobs-worker.js +47 -16
- package/src/environment-handlers/node/cli/commands/server.js +7 -2
- package/src/environment-handlers/node.js +15 -9
- package/src/error-reporting/request-details.js +28 -31
- package/src/frontend-model-controller.js +19 -13
- package/src/http-server/client/index.js +5 -13
- package/src/http-server/client/request-runner.js +26 -9
- package/src/http-server/client/request-timing.js +19 -0
- package/src/http-server/client/websocket-session.js +54 -14
- package/src/http-server/websocket-events-host.js +10 -8
- package/src/http-server/worker-handler/worker-thread.js +13 -6
- package/src/initializer.js +19 -1
- package/src/log-redactor.js +341 -0
- package/src/routes/resolver.js +32 -4
- package/src/testing/sqljs-test-database.js +73 -0
- package/src/testing/test-runner.js +529 -141
- package/src/testing/test.js +1 -1
- package/src/utils/shutdown-lifecycle.js +33 -30
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
* @module types
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Immutable identity shared by application initializers for one process lifecycle.
|
|
9
|
+
* @typedef {object} ApplicationProcessContext
|
|
10
|
+
* @property {string} type - Generic process type supplied to `configuration.initialize()`.
|
|
11
|
+
* @property {string} instanceId - Opaque identity unique to this lifecycle.
|
|
12
|
+
*/
|
|
13
|
+
|
|
7
14
|
/**
|
|
8
15
|
* @typedef {(args: {request: import("./http-server/client/request.js").default | import("./http-server/client/websocket-request.js").default, response: import("./http-server/client/response.js").default}) => Promise<void>} CorsType
|
|
9
16
|
*/
|
|
@@ -133,6 +140,7 @@
|
|
|
133
140
|
* @property {Array<"debug-low-level" | "debug" | "info" | "warn" | "error">} [levels] - Override which log levels are emitted.
|
|
134
141
|
* @property {boolean} [debugLowLevel] - Convenience flag to include very low-level debug logs.
|
|
135
142
|
* @property {boolean} [queryLogging] - Enable/disable database query logging. Defaults to true outside test and false in test.
|
|
143
|
+
* @property {string[]} [sensitiveNames] - Additional case-insensitive sensitive header/parameter names to redact from logging.
|
|
136
144
|
* @property {LoggerConfig[]} [loggers] - Logger instances (converted to outputs when configured).
|
|
137
145
|
* @property {LoggingOutputConfig[]} [outputs] - Explicit logger outputs (overrides console/file defaults when provided).
|
|
138
146
|
*/
|
package/build/configuration.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { digg } from "diggerize"
|
|
24
24
|
import gettextConfig from "gettext-universal/build/src/config.js"
|
|
25
|
+
import UUID from "pure-uuid"
|
|
25
26
|
import translate from "gettext-universal/build/src/translate.js"
|
|
26
27
|
import Ability from "./authorization/ability.js"
|
|
27
28
|
import BackgroundJobsAdapter from "./background-jobs/adapter.js"
|
|
@@ -31,6 +32,7 @@ import EventEmitter from "./utils/event-emitter.js"
|
|
|
31
32
|
import VelociousWebsocketChannelSubscribers from "./http-server/websocket-channel-subscribers.js"
|
|
32
33
|
import { CurrentConfigurationNotSetError, currentConfiguration, setCurrentConfiguration } from "./current-configuration.js"
|
|
33
34
|
import { requestDetails } from "./error-reporting/request-details.js"
|
|
35
|
+
import LogRedactor from "./log-redactor.js"
|
|
34
36
|
import { frontendModelApiManifest, frontendModelResourceClassFromDefinition, frontendModelResourceConfigurationFromDefinition, frontendModelResourcesForBackendProject } from "./frontend-models/resource-definition.js"
|
|
35
37
|
import { currentOfflineGrantSigningKey, normalizeOfflineGrantSigningKey } from "./sync/offline-grant.js"
|
|
36
38
|
import PluginRoutes from "./routes/plugin-routes.js"
|
|
@@ -41,6 +43,7 @@ import { withTrackedStack } from "./utils/with-tracked-stack.js"
|
|
|
41
43
|
import VelociousPackage from "./packages/velocious-package.js"
|
|
42
44
|
import FrontendTenantSqliteLifecycle from "./tenants/frontend-tenant-sqlite-lifecycle.js"
|
|
43
45
|
import { resolveGenerationId, resolveInitialGenerationState, resolveLifecycleSocketPath } from "./background-jobs/generation-identity.js"
|
|
46
|
+
import { runShutdownSteps } from "./utils/shutdown-lifecycle.js"
|
|
44
47
|
|
|
45
48
|
export { CurrentConfigurationNotSetError }
|
|
46
49
|
|
|
@@ -303,6 +306,16 @@ export default class VelociousConfiguration {
|
|
|
303
306
|
}
|
|
304
307
|
|
|
305
308
|
this._isInitialized = false
|
|
309
|
+
/** @type {import("./configuration-types.js").ApplicationProcessContext | undefined} */
|
|
310
|
+
this._applicationProcessContext = undefined
|
|
311
|
+
/** @type {import("./initializer.js").default[]} */
|
|
312
|
+
this._successfulInitializers = []
|
|
313
|
+
/** @type {boolean} */
|
|
314
|
+
this._applicationLifecycleInitialized = false
|
|
315
|
+
/** @type {Promise<void> | undefined} */
|
|
316
|
+
this._shutdownPromise = undefined
|
|
317
|
+
/** @type {Promise<void> | undefined} */
|
|
318
|
+
this._queuedInitializePromise = undefined
|
|
306
319
|
this._modelsInitialized = false
|
|
307
320
|
/**
|
|
308
321
|
* Invalidates model phases that started before database connections closed.
|
|
@@ -323,6 +336,8 @@ export default class VelociousConfiguration {
|
|
|
323
336
|
* @type {Promise<void> | undefined}
|
|
324
337
|
*/
|
|
325
338
|
this._initializePromise = undefined
|
|
339
|
+
/** @type {number | undefined} */
|
|
340
|
+
this._initializePromiseGeneration = undefined
|
|
326
341
|
const websocketInboundQueue = httpServer?.websocketInboundQueue
|
|
327
342
|
const websocketOutboundQueue = httpServer?.websocketOutboundQueue
|
|
328
343
|
|
|
@@ -425,6 +440,7 @@ export default class VelociousConfiguration {
|
|
|
425
440
|
* @type {((session: import("./http-server/client/websocket-session.js").default) => ReturnType<typeof JSON.parse> | Promise<ReturnType<typeof JSON.parse>>) | null} */
|
|
426
441
|
this._websocketSessionIdentityResolver = null
|
|
427
442
|
this._logging = logging
|
|
443
|
+
this._logRedactor = new LogRedactor({sensitiveNames: logging?.sensitiveNames})
|
|
428
444
|
this._mailerBackend = mailerBackend
|
|
429
445
|
this._routeResolverHooks = [...(routeResolverHooks || [])]
|
|
430
446
|
this._addDebugEndpointRouteHook()
|
|
@@ -1445,6 +1461,14 @@ export default class VelociousConfiguration {
|
|
|
1445
1461
|
}
|
|
1446
1462
|
}
|
|
1447
1463
|
|
|
1464
|
+
/**
|
|
1465
|
+
* Gets the configuration-owned structured logging redactor.
|
|
1466
|
+
* @returns {LogRedactor} - Structured logging redactor.
|
|
1467
|
+
*/
|
|
1468
|
+
getLogRedactor() {
|
|
1469
|
+
return this._logRedactor
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1448
1472
|
/**
|
|
1449
1473
|
* Runs get query logging enabled.
|
|
1450
1474
|
* @returns {boolean} - Whether database query logging is enabled.
|
|
@@ -2364,49 +2388,152 @@ export default class VelociousConfiguration {
|
|
|
2364
2388
|
* @param {string} args.type - Type identifier.
|
|
2365
2389
|
* @returns {Promise<void>} - Resolves when complete.
|
|
2366
2390
|
*/
|
|
2367
|
-
|
|
2391
|
+
initialize({type} = {type: "undefined"}) {
|
|
2392
|
+
if (this._queuedInitializePromise) return this._queuedInitializePromise
|
|
2393
|
+
|
|
2394
|
+
if (this._shutdownPromise) {
|
|
2395
|
+
return this._queueInitialize({continueAfterWaitFailure: true, type, waitFor: this._shutdownPromise})
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2368
2398
|
if (this._closeDatabaseConnectionsPromise) {
|
|
2369
|
-
|
|
2399
|
+
return this._queueInitialize({continueAfterWaitFailure: false, type, waitFor: this._closeDatabaseConnectionsPromise})
|
|
2370
2400
|
}
|
|
2371
2401
|
|
|
2402
|
+
return this._beginInitialize({type})
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
/**
|
|
2406
|
+
* Starts or joins initialization after lifecycle blockers have settled.
|
|
2407
|
+
* @param {object} args - Startup options.
|
|
2408
|
+
* @param {string} args.type - Generic application process type.
|
|
2409
|
+
* @returns {Promise<void>} - Shared startup promise.
|
|
2410
|
+
*/
|
|
2411
|
+
_beginInitialize({type}) {
|
|
2372
2412
|
const initializationGeneration = this._modelInitializationGeneration
|
|
2373
2413
|
|
|
2374
|
-
if (this.
|
|
2414
|
+
if (this._initializePromise && this._initializePromiseGeneration === initializationGeneration) {
|
|
2415
|
+
return this._initializePromise
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
if (this._initializePromise) {
|
|
2419
|
+
return this._queueInitialize({continueAfterWaitFailure: false, type, waitFor: this._initializePromise})
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
if (this._isInitialized) {
|
|
2423
|
+
this._initializePromise = Promise.resolve()
|
|
2424
|
+
this._initializePromiseGeneration = initializationGeneration
|
|
2425
|
+
|
|
2426
|
+
return this._initializePromise
|
|
2427
|
+
}
|
|
2375
2428
|
// Memoize the in-progress initialization so concurrent callers await the same
|
|
2376
2429
|
// bootstrap instead of racing. `_isInitialized` was previously set to `true`
|
|
2377
2430
|
// up front, so a second caller (e.g. a pooled runner with
|
|
2378
2431
|
// `pooledRunnerConcurrency > 1` starting several jobs on a cold child) could
|
|
2379
2432
|
// skip initialization and load models / perform a job while the first call
|
|
2380
2433
|
// was still awaiting model discovery and initializers. Mirrors connectBeacon.
|
|
2381
|
-
|
|
2382
|
-
|
|
2434
|
+
const initializePromise = this._runInitialize({initializationGeneration, type})
|
|
2435
|
+
|
|
2436
|
+
this._initializePromise = initializePromise
|
|
2437
|
+
this._initializePromiseGeneration = initializationGeneration
|
|
2383
2438
|
|
|
2384
|
-
|
|
2439
|
+
return initializePromise
|
|
2440
|
+
}
|
|
2385
2441
|
|
|
2386
|
-
|
|
2387
|
-
|
|
2442
|
+
/**
|
|
2443
|
+
* Queues one shared initialization behind an incompatible lifecycle phase.
|
|
2444
|
+
* @param {object} args - Queue options.
|
|
2445
|
+
* @param {boolean} args.continueAfterWaitFailure - Whether a completed failed shutdown still permits replacement startup.
|
|
2446
|
+
* @param {string} args.type - Replacement process type.
|
|
2447
|
+
* @param {Promise<void>} args.waitFor - Lifecycle phase that must settle first.
|
|
2448
|
+
* @returns {Promise<void>} - Shared queued startup promise.
|
|
2449
|
+
*/
|
|
2450
|
+
_queueInitialize({continueAfterWaitFailure, type, waitFor}) {
|
|
2451
|
+
if (this._queuedInitializePromise) return this._queuedInitializePromise
|
|
2452
|
+
|
|
2453
|
+
const queuedInitializePromise = (async () => {
|
|
2454
|
+
await this._waitForInitializeBlocker({continueAfterWaitFailure, waitFor})
|
|
2455
|
+
|
|
2456
|
+
if (this._shutdownPromise === waitFor) this._shutdownPromise = undefined
|
|
2457
|
+
if (this._initializePromise === waitFor) {
|
|
2458
|
+
this._initializePromise = undefined
|
|
2459
|
+
this._initializePromiseGeneration = undefined
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
const shutdownPromise = this._shutdownPromise
|
|
2463
|
+
|
|
2464
|
+
if (shutdownPromise) {
|
|
2465
|
+
await this._waitForInitializeBlocker({continueAfterWaitFailure: true, waitFor: shutdownPromise})
|
|
2466
|
+
if (this._shutdownPromise === shutdownPromise) this._shutdownPromise = undefined
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
if (this._initializePromise && this._initializePromiseGeneration !== this._modelInitializationGeneration) {
|
|
2470
|
+
const staleInitializePromise = this._initializePromise
|
|
2471
|
+
|
|
2472
|
+
await staleInitializePromise
|
|
2473
|
+
if (this._initializePromise === staleInitializePromise) {
|
|
2388
2474
|
this._initializePromise = undefined
|
|
2475
|
+
this._initializePromiseGeneration = undefined
|
|
2389
2476
|
}
|
|
2390
|
-
|
|
2391
|
-
return await this.initialize({type})
|
|
2392
2477
|
}
|
|
2393
2478
|
|
|
2394
|
-
|
|
2479
|
+
await this._beginInitialize({type})
|
|
2480
|
+
})().finally(() => {
|
|
2481
|
+
this._queuedInitializePromise = undefined
|
|
2482
|
+
})
|
|
2483
|
+
|
|
2484
|
+
this._queuedInitializePromise = queuedInitializePromise
|
|
2485
|
+
|
|
2486
|
+
return queuedInitializePromise
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
/**
|
|
2490
|
+
* Waits for a lifecycle phase before queued initialization proceeds.
|
|
2491
|
+
* @param {object} args - Wait policy.
|
|
2492
|
+
* @param {boolean} args.continueAfterWaitFailure - Whether replacement startup remains available after a failed phase.
|
|
2493
|
+
* @param {Promise<void>} args.waitFor - Lifecycle phase that must settle first.
|
|
2494
|
+
* @returns {Promise<void>} - Resolves when queued initialization may continue.
|
|
2495
|
+
*/
|
|
2496
|
+
async _waitForInitializeBlocker({continueAfterWaitFailure, waitFor}) {
|
|
2497
|
+
try {
|
|
2498
|
+
await waitFor
|
|
2499
|
+
} catch (error) {
|
|
2500
|
+
if (!continueAfterWaitFailure) throw error
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
/**
|
|
2505
|
+
* Runs one atomic framework and application initialization attempt.
|
|
2506
|
+
* @param {object} args - Initialization identity.
|
|
2507
|
+
* @param {number} args.initializationGeneration - Framework model generation.
|
|
2508
|
+
* @param {string} args.type - Generic application process type.
|
|
2509
|
+
* @returns {Promise<void>} - Resolves when initialized.
|
|
2510
|
+
*/
|
|
2511
|
+
async _runInitialize({initializationGeneration, type}) {
|
|
2512
|
+
const startsApplicationLifecycle = !this._applicationLifecycleInitialized
|
|
2513
|
+
|
|
2514
|
+
if (startsApplicationLifecycle) {
|
|
2515
|
+
this._applicationProcessContext = Object.freeze({
|
|
2516
|
+
instanceId: new UUID(4).format(),
|
|
2517
|
+
type
|
|
2518
|
+
})
|
|
2395
2519
|
}
|
|
2396
2520
|
|
|
2397
|
-
|
|
2521
|
+
try {
|
|
2398
2522
|
await this.initializeModels({type})
|
|
2399
2523
|
|
|
2400
2524
|
// Model initialization can be invalidated by a concurrent connection close.
|
|
2401
2525
|
// If models are not ready, stop without marking the configuration initialized
|
|
2402
2526
|
// so the next caller retries a full bootstrap.
|
|
2403
|
-
if (this._modelInitializationGeneration !== initializationGeneration || !this._modelsInitialized)
|
|
2527
|
+
if (this._modelInitializationGeneration !== initializationGeneration || !this._modelsInitialized) {
|
|
2528
|
+
if (startsApplicationLifecycle) this._resetApplicationLifecycle()
|
|
2529
|
+
return
|
|
2530
|
+
}
|
|
2404
2531
|
|
|
2405
2532
|
await this.getEnvironmentHandler().autoDiscoverResources(this)
|
|
2406
2533
|
this._mergeDiscoveredAbilityResources()
|
|
2407
2534
|
this._validateResourceRelationshipsOnModels()
|
|
2408
2535
|
|
|
2409
|
-
if (this._initializers) {
|
|
2536
|
+
if (startsApplicationLifecycle && this._initializers) {
|
|
2410
2537
|
const initializers = await this._initializers({configuration: this})
|
|
2411
2538
|
const {requireContext, ...restArgs} = initializers
|
|
2412
2539
|
|
|
@@ -2415,37 +2542,106 @@ export default class VelociousConfiguration {
|
|
|
2415
2542
|
if (requireContext) {
|
|
2416
2543
|
for (const initializerKey of requireContext.keys()) {
|
|
2417
2544
|
const InitializerClass = requireContext(initializerKey).default
|
|
2418
|
-
const
|
|
2545
|
+
const processContext = this._applicationProcessContext
|
|
2546
|
+
|
|
2547
|
+
if (!processContext) throw new Error("Application process context is not available during initializer startup")
|
|
2548
|
+
|
|
2549
|
+
const initializerInstance = new InitializerClass({configuration: this, processContext, type})
|
|
2419
2550
|
|
|
2420
2551
|
await initializerInstance.run()
|
|
2552
|
+
this._successfulInitializers.push(initializerInstance)
|
|
2421
2553
|
}
|
|
2422
2554
|
}
|
|
2423
2555
|
}
|
|
2424
2556
|
|
|
2557
|
+
if (startsApplicationLifecycle) this._applicationLifecycleInitialized = true
|
|
2558
|
+
|
|
2425
2559
|
if (this._modelInitializationGeneration === initializationGeneration) {
|
|
2426
2560
|
this._isInitialized = true
|
|
2427
2561
|
}
|
|
2428
|
-
}
|
|
2562
|
+
} catch (error) {
|
|
2563
|
+
if (startsApplicationLifecycle) {
|
|
2564
|
+
let teardownError
|
|
2429
2565
|
|
|
2430
|
-
|
|
2566
|
+
try {
|
|
2567
|
+
await this._teardownSuccessfulInitializers()
|
|
2568
|
+
} catch (caughtTeardownError) {
|
|
2569
|
+
teardownError = caughtTeardownError
|
|
2570
|
+
} finally {
|
|
2571
|
+
this._resetApplicationLifecycle()
|
|
2572
|
+
}
|
|
2431
2573
|
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2574
|
+
if (teardownError instanceof AggregateError) {
|
|
2575
|
+
throw new AggregateError(
|
|
2576
|
+
[error, ...teardownError.errors],
|
|
2577
|
+
"Application process startup and cleanup failed",
|
|
2578
|
+
{cause: error}
|
|
2579
|
+
)
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
if (teardownError !== undefined) {
|
|
2583
|
+
throw new AggregateError(
|
|
2584
|
+
[error, teardownError],
|
|
2585
|
+
"Application process startup and cleanup failed",
|
|
2586
|
+
{cause: error}
|
|
2587
|
+
)
|
|
2588
|
+
}
|
|
2439
2589
|
}
|
|
2590
|
+
|
|
2440
2591
|
throw error
|
|
2592
|
+
} finally {
|
|
2593
|
+
if (!this._isInitialized && this._initializePromiseGeneration === initializationGeneration) {
|
|
2594
|
+
this._initializePromise = undefined
|
|
2595
|
+
this._initializePromiseGeneration = undefined
|
|
2596
|
+
}
|
|
2441
2597
|
}
|
|
2598
|
+
}
|
|
2442
2599
|
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2600
|
+
/**
|
|
2601
|
+
* Tears down every successfully started initializer in reverse order.
|
|
2602
|
+
* @returns {Promise<void>} - Resolves when every teardown succeeds.
|
|
2603
|
+
*/
|
|
2604
|
+
async _teardownSuccessfulInitializers() {
|
|
2605
|
+
const successfulInitializers = this._successfulInitializers.splice(0).reverse()
|
|
2606
|
+
|
|
2607
|
+
await runShutdownSteps({
|
|
2608
|
+
message: "Application initializer teardown failed",
|
|
2609
|
+
steps: successfulInitializers.map((initializer) => async () => await initializer.teardown())
|
|
2610
|
+
})
|
|
2611
|
+
}
|
|
2612
|
+
|
|
2613
|
+
/** Clears application-owned lifecycle state after every teardown attempt. */
|
|
2614
|
+
_resetApplicationLifecycle() {
|
|
2615
|
+
this._applicationLifecycleInitialized = false
|
|
2616
|
+
this._applicationProcessContext = undefined
|
|
2617
|
+
this._successfulInitializers = []
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
/**
|
|
2621
|
+
* Tears down the current application lifecycle once.
|
|
2622
|
+
* @returns {Promise<void>} - Exact shared shutdown promise.
|
|
2623
|
+
*/
|
|
2624
|
+
shutdown() {
|
|
2625
|
+
if (this._shutdownPromise) return this._shutdownPromise
|
|
2626
|
+
|
|
2627
|
+
const initializePromise = this._initializePromise
|
|
2628
|
+
const shutdownPromise = (async () => {
|
|
2629
|
+
try {
|
|
2630
|
+
if (initializePromise) await initializePromise
|
|
2631
|
+
await this._teardownSuccessfulInitializers()
|
|
2632
|
+
} finally {
|
|
2633
|
+
this._resetApplicationLifecycle()
|
|
2634
|
+
this._isInitialized = false
|
|
2635
|
+
if (this._initializePromise === initializePromise) {
|
|
2636
|
+
this._initializePromise = undefined
|
|
2637
|
+
this._initializePromiseGeneration = undefined
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
})()
|
|
2641
|
+
|
|
2642
|
+
this._shutdownPromise = shutdownPromise
|
|
2643
|
+
|
|
2644
|
+
return shutdownPromise
|
|
2449
2645
|
}
|
|
2450
2646
|
|
|
2451
2647
|
/**
|
|
@@ -3312,7 +3508,9 @@ export default class VelociousConfiguration {
|
|
|
3312
3508
|
async clientErrorPayloadForError(args) {
|
|
3313
3509
|
/** @type {import("./configuration-types.js").ClientErrorPayloadReporterPayload} */
|
|
3314
3510
|
const payload = {}
|
|
3315
|
-
const
|
|
3511
|
+
const requestTiming = this.getCurrentRequestTiming()
|
|
3512
|
+
const sensitiveValues = requestTiming ? requestTiming.getLogSensitiveValues() : new Set()
|
|
3513
|
+
const details = requestDetails(args.request, {redactor: this.getLogRedactor(), sensitiveValues})
|
|
3316
3514
|
|
|
3317
3515
|
for (const reporter of this._clientErrorPayloadReporters) {
|
|
3318
3516
|
const reporterPayload = await reporter({
|
|
@@ -3328,6 +3526,32 @@ export default class VelociousConfiguration {
|
|
|
3328
3526
|
return payload
|
|
3329
3527
|
}
|
|
3330
3528
|
|
|
3529
|
+
/**
|
|
3530
|
+
* Runs one test attempt in a revocable database-access context.
|
|
3531
|
+
* @template T
|
|
3532
|
+
* @param {{revoked: boolean}} scope - Attempt-owned access scope.
|
|
3533
|
+
* @param {() => T | Promise<T>} callback - Attempt work.
|
|
3534
|
+
* @returns {T | Promise<T>} - Callback result.
|
|
3535
|
+
*/
|
|
3536
|
+
runWithTestDatabaseAccessScope(scope, callback) {
|
|
3537
|
+
return this.getEnvironmentHandler().runWithTestDatabaseAccessScope(scope, callback)
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
/**
|
|
3541
|
+
* Runs persistent framework work without inheriting a test attempt's revocable database-access scope.
|
|
3542
|
+
* @template T
|
|
3543
|
+
* @param {() => T | Promise<T>} callback - Persistent work to run.
|
|
3544
|
+
* @returns {Promise<T>} - Callback result.
|
|
3545
|
+
*/
|
|
3546
|
+
async withoutCurrentTestDatabaseAccessScope(callback) {
|
|
3547
|
+
return await this.getEnvironmentHandler().runWithCapturedTestDatabaseAccessScope(undefined, callback)
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
/** Throws when a timed-out test attempt tries to start more database work. */
|
|
3551
|
+
assertDatabaseAccessAllowed() {
|
|
3552
|
+
this.getEnvironmentHandler().assertTestDatabaseAccessAllowed()
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3331
3555
|
/**
|
|
3332
3556
|
* Runs with connections.
|
|
3333
3557
|
* @template T
|
|
@@ -3336,6 +3560,7 @@ export default class VelociousConfiguration {
|
|
|
3336
3560
|
* @returns {Promise<T>} - Resolves with the callback result.
|
|
3337
3561
|
*/
|
|
3338
3562
|
async withConnections(optionsOrCallback, callback) {
|
|
3563
|
+
this.assertDatabaseAccessAllowed()
|
|
3339
3564
|
const {
|
|
3340
3565
|
callback: actualWithConnectionsCallback,
|
|
3341
3566
|
databaseIdentifiers,
|
|
@@ -3366,6 +3591,7 @@ export default class VelociousConfiguration {
|
|
|
3366
3591
|
* @returns {Promise<T>} - Resolves with the callback result.
|
|
3367
3592
|
*/
|
|
3368
3593
|
async withTransaction({databaseIdentifier, name = "Configuration.withTransaction", ...restArgs}, callback) {
|
|
3594
|
+
this.assertDatabaseAccessAllowed()
|
|
3369
3595
|
restArgsError(restArgs)
|
|
3370
3596
|
|
|
3371
3597
|
if (!databaseIdentifier) throw new Error("Configuration.withTransaction requires a databaseIdentifier")
|
|
@@ -3379,6 +3605,7 @@ export default class VelociousConfiguration {
|
|
|
3379
3605
|
const pool = this.getDatabasePool(databaseIdentifier)
|
|
3380
3606
|
|
|
3381
3607
|
return await pool.withOperationConnection({name}, async (connection, owner) => {
|
|
3608
|
+
this.assertDatabaseAccessAllowed()
|
|
3382
3609
|
const operation = new DatabaseOperation({
|
|
3383
3610
|
configuration: this,
|
|
3384
3611
|
databaseConfiguration,
|
|
@@ -3390,7 +3617,10 @@ export default class VelociousConfiguration {
|
|
|
3390
3617
|
})
|
|
3391
3618
|
|
|
3392
3619
|
try {
|
|
3393
|
-
return await operation.transaction(async () =>
|
|
3620
|
+
return await operation.transaction(async () => {
|
|
3621
|
+
this.assertDatabaseAccessAllowed()
|
|
3622
|
+
return await callback(operation)
|
|
3623
|
+
})
|
|
3394
3624
|
} finally {
|
|
3395
3625
|
operation.complete()
|
|
3396
3626
|
}
|
|
@@ -3407,6 +3637,7 @@ export default class VelociousConfiguration {
|
|
|
3407
3637
|
* @returns {Promise<T>} - Callback result.
|
|
3408
3638
|
*/
|
|
3409
3639
|
async withDatabaseOperation({databaseConfiguration, databaseIdentifier, name = "Configuration.withDatabaseOperation", schemaGeneration, tenant, ...restArgs}, callback) {
|
|
3640
|
+
this.assertDatabaseAccessAllowed()
|
|
3410
3641
|
restArgsError(restArgs)
|
|
3411
3642
|
|
|
3412
3643
|
if (!databaseIdentifier) throw new Error("Configuration.withDatabaseOperation requires a databaseIdentifier")
|
|
@@ -3417,6 +3648,7 @@ export default class VelociousConfiguration {
|
|
|
3417
3648
|
const configurationReuseKey = pool.getConfigurationReuseKey(databaseConfiguration)
|
|
3418
3649
|
|
|
3419
3650
|
return await pool.withCapturedOperationConnection({databaseConfiguration, name}, async (connection, owner) => {
|
|
3651
|
+
this.assertDatabaseAccessAllowed()
|
|
3420
3652
|
const operation = new DatabaseOperation({
|
|
3421
3653
|
configuration: this,
|
|
3422
3654
|
databaseConfiguration,
|
|
@@ -3446,6 +3678,7 @@ export default class VelociousConfiguration {
|
|
|
3446
3678
|
async withDatabaseIdentifierConnections({callback, dbs, identifiers, name, stackLabel}) {
|
|
3447
3679
|
const stack = Error().stack
|
|
3448
3680
|
const actualCallback = async () => {
|
|
3681
|
+
this.assertDatabaseAccessAllowed()
|
|
3449
3682
|
return await withTrackedStack(stack || stackLabel, async () => {
|
|
3450
3683
|
return await callback(dbs)
|
|
3451
3684
|
})
|
|
@@ -3479,6 +3712,7 @@ export default class VelociousConfiguration {
|
|
|
3479
3712
|
* @returns {Record<string, import("./database/drivers/base.js").default>} A map of database connections with identifier as key
|
|
3480
3713
|
*/
|
|
3481
3714
|
getCurrentConnections(databaseIdentifiers = this.getDatabaseIdentifiers()) {
|
|
3715
|
+
this.assertDatabaseAccessAllowed()
|
|
3482
3716
|
/**
|
|
3483
3717
|
* Dbs.
|
|
3484
3718
|
* @type {{[key: string]: import("./database/drivers/base.js").default}} */
|
|
@@ -3568,6 +3802,7 @@ export default class VelociousConfiguration {
|
|
|
3568
3802
|
* @returns {Promise<T>} - Resolves with the callback result.
|
|
3569
3803
|
*/
|
|
3570
3804
|
async ensureConnections(optionsOrCallback, callback) {
|
|
3805
|
+
this.assertDatabaseAccessAllowed()
|
|
3571
3806
|
const {
|
|
3572
3807
|
callback: actualWithConnectionsCallback,
|
|
3573
3808
|
databaseIdentifiers,
|