@lark-apaas/fullstack-cli 1.1.66-alpha.20260902183957 → 1.1.66-alpha.20260903064712
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/package.json
CHANGED
|
@@ -18,6 +18,8 @@ const MAX_MANIFEST_BYTES = 1024 * 1024;
|
|
|
18
18
|
const MAX_READINESS_RESPONSE_BYTES = 64 * 1024;
|
|
19
19
|
const SOURCE_RETRY_INITIAL_DELAY_MS = 250;
|
|
20
20
|
const SOURCE_RETRY_MAX_DELAY_MS = 5_000;
|
|
21
|
+
const DEFAULT_SOURCE_START_DELAY_MS = 15_000;
|
|
22
|
+
const TEST_SOURCE_START_DELAY_ARG = '--miaoda-test-source-start-delay-ms=';
|
|
21
23
|
const RUNTIME_CONTROL_ENV_KEYS = new Set([
|
|
22
24
|
'MIAODA_COLD_START_DECISION_FILE',
|
|
23
25
|
'MIAODA_DEPENDENCY_READY_FILE',
|
|
@@ -72,14 +74,16 @@ const publicPort = Number(process.env.SERVER_PORT || 3000);
|
|
|
72
74
|
const logDir = path.resolve(projectRoot, process.env.LOG_DIR || 'logs');
|
|
73
75
|
const readinessPath =
|
|
74
76
|
process.env.MIAODA_NEST_READINESS_PATH || '/__innerapi__/capability/list';
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
function resolveSourceReadinessPath(baseEnv) {
|
|
78
|
+
const clientBasePath =
|
|
79
|
+
baseEnv.CLIENT_BASE_PATH?.startsWith('/') &&
|
|
80
|
+
!baseEnv.CLIENT_BASE_PATH.startsWith('//')
|
|
81
|
+
? baseEnv.CLIENT_BASE_PATH.replace(/\/+$/, '')
|
|
82
|
+
: '';
|
|
83
|
+
return clientBasePath
|
|
84
|
+
? `${clientBasePath}/__innerapi__/capability/list`
|
|
85
|
+
: readinessPath;
|
|
86
|
+
}
|
|
83
87
|
const sourceReadyTimeoutMs = positiveDuration(
|
|
84
88
|
'MIAODA_NEST_SOURCE_READY_TIMEOUT_MS',
|
|
85
89
|
60_000
|
|
@@ -89,6 +93,7 @@ const shutdownTimeoutMs = positiveDuration(
|
|
|
89
93
|
5_000
|
|
90
94
|
);
|
|
91
95
|
const drainTimeoutMs = positiveDuration('MIAODA_NEST_DRAIN_TIMEOUT_MS', 5_000);
|
|
96
|
+
const sourceStartDelayMs = sourceStartDelayForRuntime();
|
|
92
97
|
const processStartTicks =
|
|
93
98
|
readLinuxProcessStartTicks(process.pid) ||
|
|
94
99
|
String(
|
|
@@ -219,12 +224,29 @@ let resolveLifetime;
|
|
|
219
224
|
const lifetime = new Promise(resolve => {
|
|
220
225
|
resolveLifetime = resolve;
|
|
221
226
|
});
|
|
227
|
+
let firstHtmlTransferredAtMs = 0;
|
|
228
|
+
let resolveFirstHtmlTransferred;
|
|
229
|
+
const firstHtmlTransferred = new Promise(resolve => {
|
|
230
|
+
resolveFirstHtmlTransferred = resolve;
|
|
231
|
+
});
|
|
222
232
|
|
|
223
233
|
function positiveDuration(name, fallback) {
|
|
224
234
|
const value = Number(process.env[name] || fallback);
|
|
225
235
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
226
236
|
}
|
|
227
237
|
|
|
238
|
+
function sourceStartDelayForRuntime() {
|
|
239
|
+
const testArgument = process.argv
|
|
240
|
+
.slice(2)
|
|
241
|
+
.find(argument => argument.startsWith(TEST_SOURCE_START_DELAY_ARG));
|
|
242
|
+
if (!testArgument) return DEFAULT_SOURCE_START_DELAY_MS;
|
|
243
|
+
const value = Number(testArgument.slice(TEST_SOURCE_START_DELAY_ARG.length));
|
|
244
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
245
|
+
throw new Error('MIAODA_NEST_TEST_SOURCE_START_DELAY_INVALID');
|
|
246
|
+
}
|
|
247
|
+
return value;
|
|
248
|
+
}
|
|
249
|
+
|
|
228
250
|
function validateRuntimeConfiguration() {
|
|
229
251
|
if (process.env.MIAODA_NEST_BUNDLE_HANDOFF_ENABLED !== 'true') {
|
|
230
252
|
throw new Error('MIAODA_NEST_BUNDLE_HANDOFF_DISABLED');
|
|
@@ -962,6 +984,36 @@ function retain(upstream) {
|
|
|
962
984
|
};
|
|
963
985
|
}
|
|
964
986
|
|
|
987
|
+
function observeFirstCacheHtmlTransfer(request, response, upstreamResponse) {
|
|
988
|
+
if (
|
|
989
|
+
firstHtmlTransferredAtMs ||
|
|
990
|
+
request.method !== 'GET' ||
|
|
991
|
+
activeUpstream !== cacheUpstream ||
|
|
992
|
+
upstreamResponse.statusCode < 200 ||
|
|
993
|
+
upstreamResponse.statusCode >= 400 ||
|
|
994
|
+
!String(upstreamResponse.headers['content-type'] || '')
|
|
995
|
+
.toLowerCase()
|
|
996
|
+
.startsWith('text/html')
|
|
997
|
+
) {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
response.once('finish', () => {
|
|
1001
|
+
if (firstHtmlTransferredAtMs) return;
|
|
1002
|
+
firstHtmlTransferredAtMs = Date.now();
|
|
1003
|
+
resolveFirstHtmlTransferred(firstHtmlTransferredAtMs);
|
|
1004
|
+
process.stderr.write(
|
|
1005
|
+
`${JSON.stringify({
|
|
1006
|
+
event: 'miaoda_nest_html_transferred',
|
|
1007
|
+
bootId,
|
|
1008
|
+
generationId: currentGenerationId,
|
|
1009
|
+
sourceStartDelayMs,
|
|
1010
|
+
atMs: firstHtmlTransferredAtMs,
|
|
1011
|
+
elapsedMs: firstHtmlTransferredAtMs - restoreEpochMs,
|
|
1012
|
+
})}\n`
|
|
1013
|
+
);
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
|
|
965
1017
|
function createProxy() {
|
|
966
1018
|
const server = http.createServer((request, response) => {
|
|
967
1019
|
const upstream = activeUpstream;
|
|
@@ -980,6 +1032,7 @@ function createProxy() {
|
|
|
980
1032
|
headers: request.headers,
|
|
981
1033
|
},
|
|
982
1034
|
upstreamResponse => {
|
|
1035
|
+
observeFirstCacheHtmlTransfer(request, response, upstreamResponse);
|
|
983
1036
|
response.writeHead(
|
|
984
1037
|
upstreamResponse.statusCode || 502,
|
|
985
1038
|
upstreamResponse.statusMessage || '',
|
|
@@ -1588,6 +1641,18 @@ async function waitForReceipt(expectedGenerationId) {
|
|
|
1588
1641
|
if (shuttingDown) throw new Error('MIAODA_NEST_RUNTIME_STOPPING');
|
|
1589
1642
|
}
|
|
1590
1643
|
|
|
1644
|
+
async function waitForSourceStartWindow() {
|
|
1645
|
+
if (sourceStartDelayMs === 0) return;
|
|
1646
|
+
const htmlTransferredAtMs = await firstHtmlTransferred;
|
|
1647
|
+
const deadline = htmlTransferredAtMs + sourceStartDelayMs;
|
|
1648
|
+
while (!shuttingDown && Date.now() < deadline) {
|
|
1649
|
+
await new Promise(resolve =>
|
|
1650
|
+
setTimeout(resolve, Math.min(50, deadline - Date.now()))
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
if (shuttingDown) throw new Error('MIAODA_NEST_RUNTIME_STOPPING');
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1591
1656
|
async function runActionPluginInit(baseEnv) {
|
|
1592
1657
|
const record = spawnOwned(
|
|
1593
1658
|
'action-plugin-init',
|
|
@@ -1667,7 +1732,7 @@ async function startAndPromoteSource(baseEnv, expectedCapabilityIds) {
|
|
|
1667
1732
|
candidate,
|
|
1668
1733
|
sourceReadyTimeoutMs,
|
|
1669
1734
|
expectedCapabilityIds,
|
|
1670
|
-
|
|
1735
|
+
resolveSourceReadinessPath(baseEnv)
|
|
1671
1736
|
);
|
|
1672
1737
|
} catch (error) {
|
|
1673
1738
|
try {
|
|
@@ -1706,6 +1771,21 @@ async function startAndPromoteSource(baseEnv, expectedCapabilityIds) {
|
|
|
1706
1771
|
|
|
1707
1772
|
async function promoteSource(expectedGenerationId, expectedCapabilityIds) {
|
|
1708
1773
|
await waitForReceipt(expectedGenerationId);
|
|
1774
|
+
await waitForSourceStartWindow();
|
|
1775
|
+
const sourceStartingAtMs = Date.now();
|
|
1776
|
+
process.stderr.write(
|
|
1777
|
+
`${JSON.stringify({
|
|
1778
|
+
event: 'miaoda_nest_source_starting',
|
|
1779
|
+
bootId,
|
|
1780
|
+
generationId: currentGenerationId,
|
|
1781
|
+
sourceStartDelayMs,
|
|
1782
|
+
atMs: sourceStartingAtMs,
|
|
1783
|
+
elapsedMs: sourceStartingAtMs - restoreEpochMs,
|
|
1784
|
+
htmlToSourceStartMs: firstHtmlTransferredAtMs
|
|
1785
|
+
? sourceStartingAtMs - firstHtmlTransferredAtMs
|
|
1786
|
+
: 0,
|
|
1787
|
+
})}\n`
|
|
1788
|
+
);
|
|
1709
1789
|
let retryDelayMs = SOURCE_RETRY_INITIAL_DELAY_MS;
|
|
1710
1790
|
let baseEnv;
|
|
1711
1791
|
while (!shuttingDown && !baseEnv) {
|