Skip to content

Commit

Permalink
Add “Child process terminated via SIGTERM” logging to stderr
Browse files Browse the repository at this point in the history
Problem: child processes (helm, deno) can be killed (usually OOM killed) without any logs
Solution: Log “Child process terminated via SIGTERM” in that case to help identify the cause
  • Loading branch information
Nitive committed Aug 16, 2021
1 parent 25de10c commit 20e4d84
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 60 deletions.
14 changes: 2 additions & 12 deletions e2e-tests/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@ import {
assertStringIncludes,
} from "https://deno.land/std@0.93.0/testing/asserts.ts"
import { ignoreNotFoundError } from "../src/utils/ignore-not-found-error.ts"
import { waitForProcess } from "../src/utils/process.ts"

const runAllTests = Deno.env.get("RUN_ALL_TESTS") === "true"

const helmPluginDir = path.join(import.meta.url.replace("file://", ""), "../..")
const helmDenoBin = path.join(helmPluginDir, "scripts/dev.sh")
const chartsBin = path.join(helmPluginDir, "e2e-tests/charts")

function toText(bytes: Uint8Array): string {
return new TextDecoder().decode(bytes)
}

async function removeIfExists(filePath: string) {
await ignoreNotFoundError(Deno.remove(filePath, { recursive: true }))
}
Expand All @@ -37,14 +34,7 @@ async function run(args: string[], { env = {} }: RunOptions = {}) {
stderr: "piped",
})

const [status, output, error] = await Promise.all([
cmd.status(),
cmd.output(),
cmd.stderrOutput(),
])
cmd.close()

return { status, stdout: toText(output), stderr: toText(error) }
return await waitForProcess(cmd)
}

async function runShellCmd(shellCmd: string, opts?: RunOptions) {
Expand Down
29 changes: 5 additions & 24 deletions src/deno/render-chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as yaml from "https://deno.land/std@0.93.0/encoding/yaml.ts"
import * as fs from "https://deno.land/std@0.93.0/fs/mod.ts"
import * as path from "https://deno.land/std@0.93.0/path/mod.ts"
import { ignoreNotFoundError } from "../utils/ignore-not-found-error.ts"
import { waitForProcess } from "../utils/process.ts"

// deno-lint-ignore no-explicit-any
function stringifyResource(manifest: any): string {
Expand Down Expand Up @@ -91,17 +92,7 @@ export async function bundleChart(
stderr: "piped",
})

const [status, output, error] = await Promise.all([
cmd.status(),
cmd.output(),
cmd.stderrOutput(),
])
cmd.close()

if (!status.success) {
console.log(new TextDecoder().decode(output))
throw new Error(new TextDecoder().decode(error))
}
await waitForProcess(cmd, { autoReject: true })
}

export async function cleanupBundle(chartPath: string): Promise<void> {
Expand Down Expand Up @@ -138,6 +129,7 @@ export async function renderDenoChart(
cmd: [
deno,
"run",
"--v8-flags=--max-old-space-size=256",
"--unstable",
"--allow-net",
"--allow-read",
Expand All @@ -159,19 +151,8 @@ export async function renderDenoChart(
stderr: "piped",
})

const [status, output, error] = await Promise.all([
cmd.status(),
cmd.output(),
cmd.stderrOutput(),
])
cmd.close()

if (!status.success) {
console.log(new TextDecoder().decode(output))
return Promise.reject(new TextDecoder().decode(error))
}

const denoResources = JSON.parse(new TextDecoder().decode(output))
const { stdout } = await waitForProcess(cmd, { autoReject: true })
const denoResources = JSON.parse(stdout)
const templates = denoResources.map(stringifyResource).join("\n---\n")
await Deno.writeTextFile(
path.join(templateFolderPath, `import-rendered-templates.yaml`),
Expand Down
4 changes: 4 additions & 0 deletions src/helm/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export async function helmExecute(

const status = await cmd.status()
if (!status.success) {
if (status.signal === Deno.Signal.SIGTERM) {
console.error("Child process terminated via SIGTERM")
}

if (autoExitOnError) {
Deno.exit(status.code)
}
Expand Down
13 changes: 2 additions & 11 deletions src/helm/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as fs from "https://deno.land/std@0.93.0/fs/mod.ts"
import * as path from "https://deno.land/std@0.93.0/path/mod.ts"
import { parseHelmFetchArgs } from "../args/parse-helm-fetch-args.ts"
import { withErrorMsg } from "../std/mod.ts"
import { waitForProcess } from "../utils/process.ts"

export async function fetchChart(
chartBlob: string,
Expand Down Expand Up @@ -30,17 +31,7 @@ export async function fetchChart(
stderr: "piped",
})

const [status, output, error] = await Promise.all([
cmd.status(),
cmd.output(),
cmd.stderrOutput(),
])
cmd.close()

if (!status.success) {
console.log(new TextDecoder().decode(output))
return Promise.reject(new TextDecoder().decode(error))
}
await waitForProcess(cmd, { autoReject: true })

const directories = []
for await (const file of fs.expandGlob("*/", {
Expand Down
17 changes: 4 additions & 13 deletions src/helm/get-chart-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as path from "https://deno.land/std@0.93.0/path/mod.ts"
import * as yaml from "https://deno.land/std@0.93.0/encoding/yaml.ts"
import { parseHelmTemplateArgs } from "../args/parse-helm-template-args.ts"
import { ignoreNotFoundError } from "../utils/ignore-not-found-error.ts"
import { waitForProcess } from "../utils/process.ts"

const valuesAndReleaseData = `
kind: ChartContext
Expand Down Expand Up @@ -74,19 +75,9 @@ export async function getChartContext(
stderr: "piped",
})

const [output, error, status] = await Promise.all([
cmd.output(),
cmd.stderrOutput(),
cmd.status(),
])
cmd.close()

const manifests = new TextDecoder().decode(output)
const errorStr = new TextDecoder().decode(error)

if (!status.success) {
return Promise.reject(errorStr)
}
const { stdout: manifests } = await waitForProcess(cmd, {
autoReject: true,
})

// deno-lint-ignore no-explicit-any
const data = yaml.parseAll(manifests) as any[]
Expand Down
28 changes: 28 additions & 0 deletions src/utils/process.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { toText } from "./text.ts"

export async function waitForProcess(
ps: Deno.Process,
opts: { autoReject?: boolean } = {}
) {
const [status, output, error] = await Promise.all([
ps.status(),
ps.output(),
ps.stderrOutput(),
])
ps.close()

const stdout = toText(output)
let stderr = toText(error)
if (status.signal === Deno.Signal.SIGTERM) {
stderr = `Child process terminated via SIGTERM\n${stderr}`
}

if (opts.autoReject) {
if (!status.success) {
console.log(stdout)
return Promise.reject(stderr)
}
}

return { status, stdout, stderr }
}
3 changes: 3 additions & 0 deletions src/utils/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function toText(bytes: Uint8Array): string {
return new TextDecoder().decode(bytes)
}

0 comments on commit 20e4d84

Please sign in to comment.