topic/rust #2
|
@ -1,42 +0,0 @@
|
|||
name: Keep Running
|
||||
run-name: ${{ gitea.actor }} is running spotify.local CI pipeline 🚀
|
||||
on: [push]
|
||||
concurrency: 'true'
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Building project
|
||||
run: npm run build
|
||||
- name: Creating Linux Archive
|
||||
uses: vimtor/action-zip@v1.1
|
||||
with:
|
||||
files: out/kr-linux
|
||||
dest: linux.zip
|
||||
- name: Upload Linux Archive
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: linux.zip
|
||||
- name: Creating MacOS Archive
|
||||
uses: vimtor/action-zip@v1.1
|
||||
with:
|
||||
files: out/kr-macos
|
||||
dest: macos.zip
|
||||
- name: Upload MacOS Archive
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: macos.zip
|
||||
- name: Creating Windows Archive
|
||||
uses: vimtor/action-zip@v1.1
|
||||
with:
|
||||
files: out/kr-win.exe
|
||||
dest: windows.zip
|
||||
- name: Upload Windows Archive
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: windows.zip
|
|
@ -0,0 +1,28 @@
|
|||
name: Releasing
|
||||
run-name: ${{ gitea.actor }} is building a release releasing 🚀
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-pc-windows-gnu
|
||||
archive: zip
|
||||
- target: x86_64-unknown-linux-musl
|
||||
archive: tar.gz tar.xz tar.zst
|
||||
- target: x86_64-apple-darwin
|
||||
archive: zip
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Compile and release
|
||||
uses: rust-build/rust-build.action@v1.4.4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
RUSTTARGET: ${{ matrix.target }}
|
||||
ARCHIVE_TYPES: ${{ matrix.archive }}
|
|
@ -1,6 +1,2 @@
|
|||
.idea/
|
||||
node_modules/
|
||||
out/
|
||||
|
||||
# Random test file...
|
||||
0
|
||||
/target
|
||||
/.idea
|
|
@ -0,0 +1,298 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
"unicase",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "kr"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "kr"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.4.8", features = ["derive", "unicode", "wrap_help"] }
|
||||
|
||||
[profile.release]
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
opt-level = "z" # Optimize for size.
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
|
10
bin/test.sh
10
bin/test.sh
|
@ -1,18 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
SLEEP=${1:-'10'}
|
||||
EXIT=${2:-'0'}
|
||||
SLEEP=${1:-10}
|
||||
EXIT=${2:-0}
|
||||
|
||||
echo "Sleeping for $SLEEP seconds...";
|
||||
|
||||
sleep $SLEEP;
|
||||
sleep "$SLEEP";
|
||||
|
||||
echo "Waking up!";
|
||||
|
||||
if [ $EXIT > 0 ]; then
|
||||
if [ "$EXIT" -gt "0" ]; then
|
||||
>&2 echo "Exiting with error code $EXIT";
|
||||
else
|
||||
echo "Exiting with error code $EXIT";
|
||||
fi
|
||||
|
||||
exit $EXIT;
|
||||
exit "$EXIT";
|
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"name": "kr",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"bin": "src/index.js",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"build": "pkg package.json",
|
||||
"copy-local": "cp -f out/kr-linux ~/bin/kr",
|
||||
"build-local": "npm run build && npm run copy-local"
|
||||
},
|
||||
"pkg": {
|
||||
"scripts": "src/**/*.js",
|
||||
"targets": [
|
||||
"node18-linux-x64",
|
||||
"node18-macos-x64",
|
||||
"node18-win-x64"
|
||||
],
|
||||
"outputPath": "out"
|
||||
},
|
||||
"author": "Ian Wijma",
|
||||
"dependencies": {
|
||||
"pkg": "^5.8.1",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.8.10",
|
||||
"@types/yargs": "^17.0.29"
|
||||
}
|
||||
}
|
123
src/index.js
123
src/index.js
|
@ -1,123 +0,0 @@
|
|||
const Yargs = require('yargs');
|
||||
const {spawn} = require("child_process");
|
||||
|
||||
const yargs = Yargs(process.argv.splice(2))
|
||||
.scriptName('kr')
|
||||
.usage('kr [args] <process-to-run>')
|
||||
.help()
|
||||
.option('_rpm', {
|
||||
default: 0,
|
||||
description: 'The amount of Retries Per Minute, before we stop retrying',
|
||||
type: 'number'
|
||||
})
|
||||
.option('_rph', {
|
||||
default: 0,
|
||||
description: 'The amount of Retries Per Hour, before we stop retrying',
|
||||
type: 'number'
|
||||
})
|
||||
.option('_delay', {
|
||||
default: 0,
|
||||
description: 'Time in seconds we want to delay the restart with.',
|
||||
type: 'number'
|
||||
})
|
||||
|
||||
const { _ = [], _rpm: rpm, _rph: rph, _delay: delay } = yargs.argv;
|
||||
const [command, ...args ] = _;
|
||||
|
||||
if (!command) {
|
||||
return yargs.showHelp();
|
||||
}
|
||||
|
||||
const SECONDS_IN_A_MINUTE = 60;
|
||||
const SECONDS_IN_A_HOUR = 60 * 60;
|
||||
|
||||
let historyMax = 4;
|
||||
let seconds = SECONDS_IN_A_MINUTE;
|
||||
let restartName = 'minute';
|
||||
|
||||
if (rpm && rph) {
|
||||
return console.error('Currently, can not define both --rpm and --rph, please choose only one.');
|
||||
} else if (rpm) {
|
||||
historyMax = rpm
|
||||
} else if (rph) {
|
||||
historyMax = rph
|
||||
seconds = SECONDS_IN_A_HOUR
|
||||
restartName = 'hour'
|
||||
}
|
||||
|
||||
/** @type {Object<number, string>} */
|
||||
const history = {};
|
||||
|
||||
const getNow = () => Math.ceil(Date.now() / 1000); // Time in seconds
|
||||
|
||||
/** @param {string} logs */
|
||||
const pushHistory = (logs) => history[getNow() + seconds] = logs;
|
||||
|
||||
const updateHistory = () => {
|
||||
const now = getNow();
|
||||
const clearKeys = Object.keys(history)
|
||||
.filter((time) => time <= now);
|
||||
|
||||
clearKeys.forEach((key) => delete history[key]);
|
||||
}
|
||||
|
||||
const checkHistory = () => Object.keys(history).length <= historyMax;
|
||||
|
||||
const restart = () => setTimeout(() => runCommand(delay), delay * 1000);
|
||||
|
||||
const spawnCommand = () => {
|
||||
const [ spawnCommand, ...cmdArgs ] = command.split(' ');
|
||||
const spawnArgs = [...cmdArgs, ...args];
|
||||
|
||||
return spawn(spawnCommand, spawnArgs);
|
||||
}
|
||||
|
||||
const runCommand = () => {
|
||||
const runner = spawnCommand();
|
||||
|
||||
const commandLogs = [];
|
||||
|
||||
const pushLog = (logEntry) => commandLogs.push(logEntry);
|
||||
|
||||
const trimLog = () => {
|
||||
if(commandLogs.length > 5000) commandLogs.shift()
|
||||
};
|
||||
|
||||
const clearLogs = () => commandLogs.length = 0;
|
||||
|
||||
const getLogs = () => commandLogs.join('\n');
|
||||
|
||||
const handleOut = (type, message) => {
|
||||
pushLog(`[${type}]\t${message}`);
|
||||
trimLog();
|
||||
};
|
||||
|
||||
const handleExit = (exitCode) => {
|
||||
if (exitCode === 0) {
|
||||
console.log(`Exit code: ${exitCode}`);
|
||||
} else{
|
||||
console.log(`[CRASH] exit code: ${exitCode}`)
|
||||
pushHistory(getLogs());
|
||||
clearLogs();
|
||||
updateHistory();
|
||||
if (checkHistory()) {
|
||||
console.log('Restarting...');
|
||||
restart();
|
||||
} else {
|
||||
console.error(`The process crashed more then ${historyMax} times in the past ${restartName}, stop retrying.`);
|
||||
console.error(`See below the last crash log:`);
|
||||
const keys = Object.keys(history);
|
||||
const lastKey = keys[keys.length-1];
|
||||
console.log(history[lastKey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runner.on('close', (exitCode) => handleExit(exitCode))
|
||||
runner.stdout.on('data', (data) => console.log(data.toString().trim()))
|
||||
runner.stdout.on('data', (data) => handleOut('LOG', data.toString().trim()))
|
||||
runner.stderr.on('data', (data) => handleOut('ERR', data.toString().trim()))
|
||||
}
|
||||
|
||||
// Leggo!~
|
||||
runCommand();
|
|
@ -0,0 +1,132 @@
|
|||
use std::process::{Child, Command};
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use clap::{arg, Parser};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Arguments {
|
||||
// The amount of times we retry in a span of a minute, before we stop retrying
|
||||
#[arg(long, default_value_t = 0, conflicts_with = "per_hour")]
|
||||
per_minute: u8,
|
||||
// The amount of times we retry in a span of a hour, before we stop retrying
|
||||
#[arg(long, default_value_t = 0, conflicts_with = "per_minute")]
|
||||
per_hour: u8,
|
||||
// The amount of seconds we want to delay the restart with.
|
||||
#[arg(long, default_value_t = 0)]
|
||||
delay: u8,
|
||||
|
||||
#[arg()]
|
||||
command: String
|
||||
}
|
||||
|
||||
const SECONDS_IN_A_MINUTE: u16 = 60;
|
||||
const SECONDS_IN_A_HOUR: u16 = 60 * 60;
|
||||
|
||||
struct Retry {
|
||||
command: String,
|
||||
history: Vec<u64>,
|
||||
max_retries: u8,
|
||||
timespan: u16,
|
||||
restart_delay: u8,
|
||||
restart_name: String
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let arguments = Arguments::parse();
|
||||
|
||||
let mut retry: Retry = Retry {
|
||||
command: arguments.command,
|
||||
history: Vec::new(),
|
||||
max_retries: 4,
|
||||
timespan: SECONDS_IN_A_MINUTE,
|
||||
restart_delay: arguments.delay,
|
||||
restart_name: "minute".to_string(),
|
||||
};
|
||||
|
||||
if arguments.per_minute > 0 {
|
||||
retry.max_retries = arguments.per_minute;
|
||||
} else if arguments.per_hour > 0 {
|
||||
retry.max_retries = arguments.per_hour;
|
||||
retry.timespan = SECONDS_IN_A_HOUR;
|
||||
retry.restart_name = "hour".to_string();
|
||||
}
|
||||
|
||||
run_command(&mut retry)
|
||||
}
|
||||
|
||||
fn get_now() -> u64 {
|
||||
return SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
}
|
||||
|
||||
fn push_history(retry: &mut Retry) {
|
||||
retry.history.push(get_now() + u64::from(retry.timespan));
|
||||
}
|
||||
|
||||
fn update_history(retry: &mut Retry) {
|
||||
let now = get_now();
|
||||
let clear_times: Vec<u64> = retry
|
||||
.history
|
||||
.iter()
|
||||
.filter(|&time| time <= &now)
|
||||
.map(|&time| time)
|
||||
.collect();
|
||||
|
||||
for time in clear_times {
|
||||
retry.history.retain(|&h| h != time);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_history(retry: &Retry) -> bool {
|
||||
return retry.history.len().lt(&usize::from(retry.max_retries))
|
||||
}
|
||||
|
||||
fn spawn_process(retry: &Retry) -> std::io::Result<Child> {
|
||||
let mut command_parts: Vec<String> = retry
|
||||
.command
|
||||
.split_whitespace()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
|
||||
let mut command: Command = Command::new(&command_parts[0]);
|
||||
command_parts.remove(0);
|
||||
command.args(command_parts);
|
||||
|
||||
return command.spawn();
|
||||
}
|
||||
|
||||
fn run_command(retry: &mut Retry) {
|
||||
let mut process = spawn_process(retry)
|
||||
.expect("Process failed on startup");
|
||||
|
||||
let exit_code = match process.wait() {
|
||||
Ok(exit_code) => exit_code,
|
||||
Err(err) => {
|
||||
eprintln!("Failed to wait for process: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if exit_code.success() {
|
||||
println!("Exit code: {}", exit_code);
|
||||
} else {
|
||||
println!("[CRASH] exit code: {}", exit_code);
|
||||
push_history(retry);
|
||||
update_history(retry);
|
||||
if check_history(retry) {
|
||||
println!("Restarting...");
|
||||
restart(retry);
|
||||
} else {
|
||||
print!("The process has crashed more then {} times in the past {}, stop restarting\n", retry.max_retries, retry.restart_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn restart(retry: &mut Retry) {
|
||||
sleep(Duration::from_secs(u64::from(retry.restart_delay)));
|
||||
|
||||
run_command(retry);
|
||||
}
|
Loading…
Reference in New Issue