This commit is contained in:
Jarek Krochmalski committed 2026-03-03 10:17:41 +01:00
1 parent d51bfb0d60
commit c26fa2d10f
4 files changed
+69 -43

No files matched your search

+12 -2
View File
@@ -2616,6 +2616,9 @@ async function getRegistryBearerToken(registry: string, repo: string): Promise<s
return null;
}
// Drain 401 response body before bearer token fetch (required by Node.js/Undici for connection reuse)
await drainResponse(challengeResponse);
// Parse bearer challenge: Bearer realm="...",service="...",scope="..."
const realmMatch = wwwAuth.match(/realm="([^"]+)"/i);
const serviceMatch = wwwAuth.match(/service="([^"]+)"/i);
@@ -2659,7 +2662,9 @@ async function getRegistryBearerToken(registry: string, repo: string): Promise<s
} catch (e) {
const errorMsg = e instanceof Error ? e.message : String(e);
console.error('[Registry] Failed to get bearer token:', errorMsg);
const cause = (e as any)?.cause;
const causeMsg = cause ? ` (cause: ${cause})` : '';
console.error('[Registry] Failed to get bearer token:', errorMsg + causeMsg);
return null;
}
}
@@ -2725,6 +2730,9 @@ export async function getRegistryAuthHeader(
return null;
}
// Drain 401 response body before bearer token fetch (required by Node.js/Undici for connection reuse)
await drainResponse(challengeResponse);
// Parse bearer challenge: Bearer realm="...",service="...",scope="..."
const realmMatch = wwwAuth.match(/realm="([^"]+)"/i);
const serviceMatch = wwwAuth.match(/service="([^"]+)"/i);
@@ -2767,7 +2775,9 @@ export async function getRegistryAuthHeader(
} catch (e) {
const errorMsg = e instanceof Error ? e.message : String(e);
console.error('[Registry] Failed to get auth header:', errorMsg);
const cause = (e as any)?.cause;
const causeMsg = cause ? ` (cause: ${cause})` : '';
console.error('[Registry] Failed to get auth header:', errorMsg + causeMsg);
return null;
}
}
+26 -4
View File
@@ -414,6 +414,11 @@ function cleanupRecentEvents(): void {
async function sendEnvironmentConfigs(): Promise<void> {
const environments = await getEnvironments();
const activeIds = new Set<number>();
const lines: string[] = [];
const enqueue = (msg: Record<string, unknown>) => {
lines.push(JSON.stringify(msg));
};
for (const env of environments) {
// Skip hawser-edge (events come via WebSocket)
@@ -446,7 +451,7 @@ async function sendEnvironmentConfigs(): Promise<void> {
// Only send if env has metrics or activity collection enabled
if (env.collectMetrics === false && env.collectActivity === false) continue;
sendToGo({
enqueue({
type: 'configure',
envId: env.id,
name: env.name,
@@ -461,7 +466,7 @@ async function sendEnvironmentConfigs(): Promise<void> {
// Remove envs that are no longer active
for (const envId of configuredEnvs) {
if (!activeIds.has(envId)) {
sendToGo({ type: 'remove', envId });
enqueue({ type: 'remove', envId });
configuredEnvs.delete(envId);
envNames.delete(envId);
}
@@ -469,11 +474,18 @@ async function sendEnvironmentConfigs(): Promise<void> {
// Send settings
const metricsInterval = await getMetricsCollectionInterval();
sendToGo({ type: 'set_metrics_interval', intervalMs: metricsInterval });
enqueue({ type: 'set_metrics_interval', intervalMs: metricsInterval });
const eventMode = await getEventCollectionMode();
const pollInterval = await getEventPollInterval();
sendToGo({ type: 'set_event_mode', mode: eventMode, pollIntervalMs: pollInterval });
enqueue({ type: 'set_event_mode', mode: eventMode, pollIntervalMs: pollInterval });
// Single atomic write — avoids pipe backpressure on low-memory ARM devices
// where multiple rapid writes can overflow small OS pipe buffers (4-16KB on
// some ARM Linux configs) before Go has drained them.
if (lines.length > 0 && proc?.stdin?.writable) {
proc.stdin.write(lines.join('\n') + '\n');
}
}
// ---------------------------------------------------------------------------
@@ -544,6 +556,16 @@ export async function startSubprocesses(): Promise<void> {
stdio: ['pipe', 'pipe', 'inherit']
});
// Prevent unhandled 'error' events on stdin from destroying the pipe.
// Without this, any write error (e.g. EPIPE on a momentarily full pipe buffer
// on low-memory systems) destroys the stream, sending EOF to Go and causing
// it to exit — which looks like a mysterious restart loop on Raspberry Pi.
proc.stdin?.on('error', (err: NodeJS.ErrnoException) => {
if (!isShuttingDown) {
console.error('[SubprocessManager] stdin pipe error:', err.message);
}
});
// Start reading stdout
readStdout();