fix: keep pod log streams alive
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# 2.5.2-rc.1
|
||||
|
||||
## Fixed
|
||||
|
||||
- Keep server-side Kubernetes log streams active with a 5-second idle heartbeat, below common intermediary idle timeouts.
|
||||
- Retry transient Kubernetes log socket and stream closures; permanent TLS certificate errors remain terminal.
|
||||
|
||||
## Changed
|
||||
|
||||
- Prefix CLI log lines with the originating pod name instead of the target service name.
|
||||
+1
-1
@@ -86,7 +86,7 @@ export async function runLogs(
|
||||
write(service ?? event.pod ?? project, event.message, true);
|
||||
continue;
|
||||
}
|
||||
write(event.targetName || service || project, event.message, false);
|
||||
write(event.pod || event.targetName || service || project, event.message, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ function cloneCommand<T extends object>(command: T): T {
|
||||
export const main = defineCommand({
|
||||
meta: {
|
||||
name: "kuber",
|
||||
version: "2.5.1",
|
||||
version: "2.5.2-rc.1",
|
||||
description: "Docker Compose -> K8s translation layer",
|
||||
},
|
||||
args: {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@dmgnr/kuber",
|
||||
"version": "2.5.1",
|
||||
"version": "2.5.2-rc.1",
|
||||
"description": "Docker Compose to Kubernetes translation layer",
|
||||
"bin": {
|
||||
"kuber": "dist/index.js"
|
||||
|
||||
@@ -40,10 +40,19 @@ function logError(error: unknown): KubernetesLogError {
|
||||
error && typeof error === "object" && "code" in error
|
||||
? error.code
|
||||
: undefined;
|
||||
const transientNetworkCodes = new Set([
|
||||
"ECONNRESET", "ETIMEDOUT", "EPIPE", "ECONNREFUSED", "EHOSTUNREACH",
|
||||
"ENETUNREACH", "ECONNABORTED", "EAI_AGAIN", "UND_ERR_SOCKET",
|
||||
"UND_ERR_CONNECT_TIMEOUT",
|
||||
]);
|
||||
const message = error instanceof Error ? error.message : "";
|
||||
return new KubernetesLogError(
|
||||
error instanceof Error ? error.message : "Kubernetes log request failed",
|
||||
code === undefined &&
|
||||
(status === undefined || status === 408 || status === 429 || status >= 500),
|
||||
typeof code === "string"
|
||||
? transientNetworkCodes.has(code)
|
||||
: status === undefined && /socket hang up|socket closed/i.test(message)
|
||||
? true
|
||||
: status === undefined || status === 408 || status === 429 || status >= 500,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -438,7 +438,7 @@ export class LogService {
|
||||
const discoveryInterval = positiveInteger(input.discoveryIntervalMs, 2_000);
|
||||
const heartbeatInterval = positiveInteger(
|
||||
input.heartbeatIntervalMs,
|
||||
15_000,
|
||||
5_000,
|
||||
);
|
||||
const retryInterval = positiveInteger(input.retryIntervalMs, 1_000);
|
||||
const queue = new BoundedAsyncQueue<LogEvent>(capacity);
|
||||
@@ -489,7 +489,11 @@ export class LogService {
|
||||
signal,
|
||||
(event) => queue.push(event),
|
||||
);
|
||||
if (!signal.aborted) completed.add(key);
|
||||
if (!signal.aborted)
|
||||
throw new KubernetesLogError(
|
||||
"Kubernetes log stream ended unexpectedly",
|
||||
true,
|
||||
);
|
||||
} catch (error) {
|
||||
if (!isAbort(signal)) {
|
||||
await pushError(error, source);
|
||||
|
||||
@@ -58,7 +58,7 @@ describe("logs API command runner", () => {
|
||||
},
|
||||
]);
|
||||
expect(output).toEqual([
|
||||
["web", "ready", false],
|
||||
["web-1", "ready", false],
|
||||
["web api", "disconnected", true],
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -650,7 +650,7 @@ describe("LogService", () => {
|
||||
expect(error).toMatchObject({
|
||||
pod: "web-abc",
|
||||
container: "web",
|
||||
retryable: false,
|
||||
retryable: true,
|
||||
});
|
||||
expect(error?.message).toMatch(
|
||||
/socket.*connection.*closed|socket hang up|fetch failed/i,
|
||||
|
||||
Reference in New Issue
Block a user