[Housekeeping] Close system port when jobs are cancelled (#182)

* Created a test setup that works

* Refactored test setup into real-world fixes
This commit is contained in:
Kieran 2024-04-10 22:13:19 -07:00 committed by GitHub
parent e984c05298
commit c36e33e1fd
6 changed files with 52 additions and 3 deletions

View file

@ -8,7 +8,7 @@ FROM ${DEV_IMAGE}
# Install debian packages
RUN apt-get update -qq
RUN apt-get install -y inotify-tools ffmpeg curl git openssh-client \
python3 python3-pip python3-setuptools python3-wheel python3-dev locales
python3 python3-pip python3-setuptools python3-wheel python3-dev locales procps
# Install nodejs
RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh

View file

@ -45,7 +45,7 @@ defmodule Pinchflat.Notifications.CommandRunner do
"""
@impl AppriseCommandRunner
def version do
case System.cmd(backend_executable(), ["--version"]) do
case CliUtils.wrap_cmd(backend_executable(), ["--version"]) do
{output, 0} ->
output
|> String.split(~r{\r?\n})

View file

@ -5,6 +5,23 @@ defmodule Pinchflat.Utils.CliUtils do
alias Pinchflat.Utils.StringUtils
@doc """
Wraps a command in a shell script that will terminate
the command if stdin is closed. Useful for stopping
commands if the job runner is cancelled.
Delegates to `System.cmd/3` and any options/output
are passed through.
Returns {binary(), integer()}
"""
def wrap_cmd(command, args, opts \\ []) do
wrapper_command = Path.join(:code.priv_dir(:pinchflat), "cmd_wrapper.sh")
actual_command = [command] ++ args
System.cmd(wrapper_command, actual_command, opts)
end
@doc """
Parses a list of command options into a list of strings suitable for passing to
`System.cmd/3`.

View file

@ -37,7 +37,7 @@ defmodule Pinchflat.YtDlp.CommandRunner do
formatted_command_opts = [url] ++ CliUtils.parse_options(all_opts)
Logger.info("[yt-dlp] called with: #{Enum.join(formatted_command_opts, " ")}")
case System.cmd(command, formatted_command_opts, stderr_to_stdout: true) do
case CliUtils.wrap_cmd(command, formatted_command_opts, stderr_to_stdout: true) do
{_, 0} ->
# IDEA: consider deleting the file after reading it. It's in the tmp dir, so it's not
# a huge deal, but it's still a good idea to clean up after ourselves.

26
priv/cmd_wrapper.sh Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# This script is a wrapper for other programs
# that ensures they are killed when stdin closes
# (eg: a job terminates)
# Start the program in the background
exec "$@" &
pid1=$!
# Silence warnings from here on
exec >/dev/null 2>&1
# Read from stdin in the background and
# kill running program when stdin closes
exec 0<&0 $(
while read; do :; done
kill -KILL $pid1
) &
pid2=$!
# Clean up
wait $pid1
ret=$?
kill -KILL $pid2
exit $ret

View file

@ -3,6 +3,12 @@ defmodule Pinchflat.Utils.CliUtilsTest do
alias Pinchflat.Utils.CliUtils
describe "wrap_cmd/3" do
test "delegates to System.cmd/3" do
assert {"output\n", 0} = CliUtils.wrap_cmd("echo", ["output"])
end
end
describe "parse_options/1" do
test "it converts symbol k-v arg keys to kebab case" do
assert ["--buffer-size", "1024"] = CliUtils.parse_options(buffer_size: 1024)