From 9b95cfc543c516a2664cc10d8878d10bcff31e31 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 30 Sep 2021 12:53:58 +0930 Subject: [PATCH] fix: ensure we always kill orphaned unraid-api processes --- app/supervisor.ts | 24 ++++++++-- package-lock.json | 112 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 133 insertions(+), 4 deletions(-) diff --git a/app/supervisor.ts b/app/supervisor.ts index f057e62bc..e784f60eb 100644 --- a/app/supervisor.ts +++ b/app/supervisor.ts @@ -5,6 +5,7 @@ import locatePath from 'locate-path'; import psList from 'ps-list'; import { cyan, green, yellow, red } from 'nanocolors'; import intervalToHuman from 'interval-to-human'; +import killProcess from 'fkill'; const createLogger = (namespace: string) => { const ns = namespace.toUpperCase(); @@ -38,7 +39,7 @@ const instances = 1; const maxRestarts = 100; const logger = createLogger('supervisor'); -let apiPid: number; +let apiPid: number | undefined; const isApiRunning = async () => { const list = await psList(); const api = list.find(process => { @@ -59,9 +60,24 @@ const sleep = async (ms: number) => new Promise(resolve => { export const startApi = async (restarts = 0, shouldRestart = true) => { const isRunning = await isApiRunning(); - if (isRunning) { - logger.debug('%s process is running with pid %s', appName, apiPid); - return; + if (isRunning && apiPid) { + logger.debug('Killing orphaned %s process with pid %s', appName, apiPid); + await killProcess(apiPid); + apiPid = undefined; + + // Wait 1s for the old process to die + await sleep(1_000); + + // Should be killed by now + const isRunning = await isApiRunning(); + // If this is still somehow running then we need to bail. + // This should only happen if you're running supervisor as a + // user with less privileges then the one who started + // the unraid-api process we're trying to kill. + if (isRunning) { + process.exitCode = 1; + return; + } } // Get an absolute path to the API binary diff --git a/package-lock.json b/package-lock.json index ae0d339c2..6f36772fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6811,6 +6811,29 @@ "resolve-dir": "^1.0.1" } }, + "fkill": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/fkill/-/fkill-7.2.1.tgz", + "integrity": "sha512-eN9cmsIlRdq06wu3m01OOEgQf5Xh/M7REm0jfZ4eL3V3XisjXzfRq3iyqtKS+FhO6wB36FvWRiRGdeSx5KpLAQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.1.0", + "arrify": "^2.0.1", + "execa": "^5.0.0", + "pid-port": "^0.1.0", + "process-exists": "^4.0.0", + "ps-list": "^7.2.0", + "taskkill": "^3.1.0" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + } + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -10700,6 +10723,15 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, + "pid-port": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pid-port/-/pid-port-0.1.1.tgz", + "integrity": "sha512-boqPJtSgZC6KOgXKNPC+/XR3xwVtpOtaLa7JLcdf8jfVe0ZM2TwllBXxxLUO8GQbOLJ4/hEtf2+L1QCKbaoHUg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, "pidusage": { "version": "2.0.21", "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.21.tgz", @@ -10852,6 +10884,23 @@ "parse-ms": "^2.1.0" } }, + "process-exists": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/process-exists/-/process-exists-4.1.0.tgz", + "integrity": "sha512-BBJoiorUKoP2AuM5q/yKwIfT1YWRHsaxjW+Ayu9erLhqKOfnXzzVVML0XTYoQZuI1YvcWKmc1dh06DEy4+KzfA==", + "dev": true, + "requires": { + "ps-list": "^6.3.0" + }, + "dependencies": { + "ps-list": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ps-list/-/ps-list-6.3.0.tgz", + "integrity": "sha512-qau0czUSB0fzSlBOQt0bo+I2v6R+xiQdj78e1BR/Qjfl5OHWJ/urXi8+ilw1eHe+5hSeDI1wrwVTgDp2wst4oA==", + "dev": true + } + } + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -12817,6 +12866,69 @@ "xtend": "^4.0.0" } }, + "taskkill": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/taskkill/-/taskkill-3.1.0.tgz", + "integrity": "sha512-5KcOFzPvd1nGFVrmB7H4+QAWVjYOf//+QTbOj0GpXbqtqbKGWVczG+rq6VhXAtdtlKLTs16NAmHRyF5vbggQ2w==", + "dev": true, + "requires": { + "arrify": "^2.0.1", + "execa": "^3.3.0" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + }, + "execa": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", + "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", + "dev": true + } + } + }, "temp-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", diff --git a/package.json b/package.json index 60182ef52..d4c79b43d 100644 --- a/package.json +++ b/package.json @@ -147,6 +147,7 @@ "cz-conventional-changelog": "3.3.0", "dedent-tabs": "^0.9.0", "eslint": "^7.32.0", + "fkill": "^7.2.1", "interval-to-human": "^0.1.1", "modclean": "^3.0.0-beta.1", "ms": "^2.1.3",