Compare commits

..

5 Commits

Author SHA1 Message Date
Brock H Caldwell
adb79db8f5 feat: allows configuring the worker service and processes via command options and env vars 2025-11-04 12:19:37 -06:00
Brock H Caldwell
9ca87af938 wip: generates supervisord config at runtime 2025-11-04 09:54:41 -06:00
Brock H Caldwell
b01840b111 fix: adds process for async transport to worker 2025-11-03 16:35:26 -06:00
Brock H Caldwell
1759b6dfdc fix: send monitors to new transport 2025-11-03 14:45:29 -06:00
Brock H Caldwell
2d3bc35e45 fix: incorrect transport for scheduler 2025-11-02 23:04:51 -06:00
14 changed files with 213 additions and 80 deletions

View File

@@ -1,14 +1,19 @@
# torsearch-app is built from this base # torsearch-app is built from this base
export APP_FRANKENPHP_TAG=php8.4 export APP_FRANKENPHP_TAG=php8.4
docker buildx build --platform=linux/amd64 -f docker/Dockerfile.base.app -t code.caldwell.digital/home/torsearch-base:${APP_FRANKENPHP_TAG} -t code.caldwell.digital/home/torsearch-base:latest --build-arg "FRANKENPHP_TAG=${APP_FRANKENPHP_TAG}" . docker buildx build --platform=linux/amd64,linux/arm64 -f docker/Dockerfile.base.app -t code.caldwell.digital/home/torsearch-base:${APP_FRANKENPHP_TAG} -t code.caldwell.digital/home/torsearch-base:latest --build-arg "FRANKENPHP_TAG=${APP_FRANKENPHP_TAG}" .
docker push code.caldwell.digital/home/torsearch-base:${APP_FRANKENPHP_TAG} docker push code.caldwell.digital/home/torsearch-base:${APP_FRANKENPHP_TAG}
docker push code.caldwell.digital/home/torsearch-base:latest docker push code.caldwell.digital/home/torsearch-base:latest
# torsearch-worker & torsearch-scheduler are built from this base # torsearch-worker & torsearch-scheduler are built from this base
export WORKER_FRANKENPHP_TAG=php8.4-alpine export WORKER_FRANKENPHP_TAG=php8.4-alpine
docker buildx build --platform=linux/amd64 -f docker/Dockerfile.base.worker -t code.caldwell.digital/home/torsearch-base-worker:${WORKER_FRANKENPHP_TAG} -t code.caldwell.digital/home/torsearch-base-worker:latest --build-arg "FRANKENPHP_TAG=${WORKER_FRANKENPHP_TAG}" . docker buildx build --platform=linux/amd64,linux/arm64 -f docker/Dockerfile.base.worker -t code.caldwell.digital/home/torsearch-base-worker:${WORKER_FRANKENPHP_TAG} -t code.caldwell.digital/home/torsearch-base-worker:latest --build-arg "FRANKENPHP_TAG=${WORKER_FRANKENPHP_TAG}" .
docker push code.caldwell.digital/home/torsearch-base-worker:${WORKER_FRANKENPHP_TAG} docker push code.caldwell.digital/home/torsearch-base-worker:${WORKER_FRANKENPHP_TAG}
docker push code.caldwell.digital/home/torsearch-base-worker:latest docker push code.caldwell.digital/home/torsearch-base-worker:latest
# torsearch-worker-supervisord
export ALPINE_VERSION=3.22
docker buildx build --platform=linux/amd64,linux/arm64 -f docker/Dockerfile.base.worker -t code.caldwell.digital/home/torsearch-base-worker-supervisord:latest --build-arg "ALPINE_VERSION=${ALPINE_VERSION}" .
docker push code.caldwell.digital/home/torsearch-base-worker-supervisord:latest

View File

@@ -33,12 +33,11 @@ services:
worker: worker:
# build: build:
# dockerfile: docker/Dockerfile.base.worker dockerfile: docker/Dockerfile.worker
# context: . context: .
# args: args:
# FRANKENPHP_TAG: php8.4-alpine APP_VERSION: latest
image: torsearch-alpine
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- $PWD:/app - $PWD:/app
@@ -46,22 +45,22 @@ services:
tty: true tty: true
environment: environment:
TZ: America/Chicago TZ: America/Chicago
# command: php /app/bin/console messenger:consume async --time-limit=3600 -vv command: --download 2 --async
scheduler: scheduler:
build: build:
dockerfile: docker/Dockerfile.base.worker dockerfile: docker/Dockerfile.worker
context: . context: .
args: args:
FRANKENPHP_TAG: php8.4-alpine APP_VERSION: latest
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- $PWD:/app - $PWD:/app
- $PWD/var/download:/var/download
tty: true
environment: environment:
TZ: America/Chicago TZ: America/Chicago
command: php /app/bin/console messenger:consume scheduler_monitor -vv WORKER_MONITOR: 2
tty: true
redis: redis:

View File

@@ -22,7 +22,7 @@ framework:
check_delayed_interval: 60000 check_delayed_interval: 60000
queue_name: download queue_name: download
retry_strategy: retry_strategy:
max_retries: 1 max_retries: 3
multiplier: 1 multiplier: 1
monitor: monitor:
@@ -58,10 +58,10 @@ framework:
# 'App\Message\YourMessage': async # 'App\Message\YourMessage': async
'App\Download\Action\Command\DownloadMediaCommand': download 'App\Download\Action\Command\DownloadMediaCommand': download
'App\Download\Action\Command\DownloadSeasonCommand': async 'App\Download\Action\Command\DownloadSeasonCommand': async
'App\Monitor\Action\Command\MonitorTvEpisodeCommand': async 'App\Monitor\Action\Command\MonitorTvEpisodeCommand': monitor
'App\Monitor\Action\Command\MonitorTvSeasonCommand': async 'App\Monitor\Action\Command\MonitorTvSeasonCommand': monitor
'App\Monitor\Action\Command\MonitorTvShowCommand': async 'App\Monitor\Action\Command\MonitorTvShowCommand': monitor
'App\Monitor\Action\Command\MonitorMovieCommand': async 'App\Monitor\Action\Command\MonitorMovieCommand': monitor
'App\Torrentio\Action\Command\GetTvShowOptionsCommand': media_cache 'App\Torrentio\Action\Command\GetTvShowOptionsCommand': media_cache
# when@test: # when@test:

View File

@@ -1,19 +1,29 @@
ARG FRANKENPHP_TAG #####
# This version of Torsearch runs the scheduler, downloader, and worker
# in a single container. Each process is managerd by supervisord
# and can be configured via environment variables and more
# than one of these containers cans till be run.
#####
ARG ALPINE_VERSION="3.22"
FROM alpine:${ALPINE_VERSION} AS build_stage
FROM dunglas/frankenphp:${FRANKENPHP_TAG} RUN apk add --no-cache \
curl \
php84 \
php84-curl \
php84-fileinfo \
php84-gd \
php84-mbstring \
php84-mysqli \
php84-opcache \
php84-openssl \
php84-pdo_mysql \
supervisor
ENV SERVER_NAME=":80" RUN ln -s /usr/bin/php84 /usr/bin/php
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
ARG APP_VERSION="0.dev" RUN mkdir -p /etc/supervisor/conf.d
ENV APP_VERSION="${APP_VERSION}"
RUN install-php-extensions \ # We start supervisord and supervisord starts
pdo_mysql \ # respective service in the configuration file.
gd \ ENTRYPOINT ["/app/bin/console", "init:worker"]
intl \
zip \
opcache
RUN apk add --no-cache wget

View File

@@ -9,32 +9,18 @@ ARG APP_VERSION="latest"
FROM code.caldwell.digital/home/torsearch-app:${APP_VERSION} AS base_image FROM code.caldwell.digital/home/torsearch-app:${APP_VERSION} AS base_image
FROM alpine:3.22 AS build_stage FROM code.caldwell.digital/home/torsearch-base-worker-supervisord:latest
ENV APP_VERSION=${APP_VERSION}
COPY --from=base_image --chown=1000:1000 /app /app COPY --from=base_image --chown=1000:1000 /app /app
COPY docker/ /app/docker
RUN apk add --no-cache \
curl \
nginx \
php84 \
php84-ctype \
php84-curl \
php84-dom \
php84-fileinfo \
php84-fpm \
php84-gd \
php84-mbstring \
php84-mysqli \
php84-opcache \
php84-openssl \
php84-pdo_mysql \
php84-tokenizer \
supervisor
RUN ln -s /usr/bin/php84 /usr/bin/php
COPY docker/worker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# We start supervisord and supervisord starts # We start supervisord and supervisord starts
# respective service in the configuration file. # respective service in the configuration file.
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] ENTRYPOINT ["/app/bin/console", "init:worker"]
# Message transports can be enabled by passing them as command options.
# Inlcluding a number with the option will start that amount of processes
# for the transport. Not supplying a number will default to 1.
# --download --monitor OR --download 2 --monitor

10
docker/worker/async.conf Normal file
View File

@@ -0,0 +1,10 @@
[program:torsearch-worker]
command=/app/bin/console messenger:consume async -vv --time-limit 3600
numprocs=1
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d

View File

@@ -0,0 +1,10 @@
[program:torsearch-downloader]
command=/app/bin/console messenger:consume download -vv --time-limit 3600
numprocs=1
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d

View File

@@ -0,0 +1,10 @@
[program:torsearch-scheduler]
command=/app/bin/console messenger:consume scheduler_monitor monitor -vv --time-limit 21600
numprocs=1
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d

View File

@@ -3,25 +3,3 @@ nodaemon=true
logfile=/dev/null logfile=/dev/null
logfile_maxbytes=0 logfile_maxbytes=0
pidfile=/run/supervisord.pid pidfile=/run/supervisord.pid
[program:torsearch-worker]
command=/app/bin/console messenger:consume download -vv --time-limit 3600
numprocs=1
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d
[program:torsearch-scheduler]
command=/app/bin/console messenger:consume monitor -vv
numprocs=1
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d

View File

@@ -0,0 +1,90 @@
<?php
namespace App\Base\Framework\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Twig\Environment;
class InitWorker extends Command
{
public function __construct(
private Environment $twig,
) {
parent::__construct();
}
protected function configure(): void
{
$this
->setName('init:worker')
->addOption('async', null, InputOption::VALUE_OPTIONAL, 'Run the async worker.',false)
->addOption('download', null, InputOption::VALUE_OPTIONAL, 'Run the download worker.', false)
->addOption('monitor', null, InputOption::VALUE_OPTIONAL, 'Run the monitor worker.', false)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$configFile = $this->twig->render("config/supervisord.conf.twig", []);
if ($this->optionExists($input, $output, 'async')) {
$configFile .= $this->twig->render("config/async.conf.twig", [
'replicas' => $this->getOptionValue('async', $input),
]) . "\n\n";
}
if ($this->optionExists($input, $output, 'download')) {
$configFile .= $this->twig->render("config/download.conf.twig", [
'replicas' => $this->getOptionValue('download', $input),
]). "\n\n";
}
if ($this->optionExists($input, $output, 'monitor')) {
$configFile .= $this->twig->render("config/monitor.conf.twig", [
'replicas' => $this->getOptionValue('monitor', $input),
]). "\n\n";
}
if ("" !== $configFile) {
$output->writeln("[init:worker] Writing /etc/supervisor/conf.d/supervisord.conf");
file_put_contents("/etc/supervisor/conf.d/supervisord.conf", $configFile);
$output->writeln("[init:worker] Starting supervisord");
shell_exec("/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf");
return Command::SUCCESS;
}
$output->writeln("[init:worker] No workers selected. Exiting.");
return Command::FAILURE;
}
private function optionExists(InputInterface $input, OutputInterface $output, string $option): bool
{
if ($input->getOption($option) !== false) {
$value = $input->getOption($option) ?? 1;
$output->writeln("[init:worker] transport: $option // $value // input var");;
return true;
}
$optionKey = 'WORKER_' . strtoupper($option);
if (array_key_exists($optionKey, $_SERVER) && $_SERVER[$optionKey] !== null && $_SERVER[$optionKey] !== '') {
$output->writeln("[init:worker] transport: $option // $_SERVER[$optionKey] // env var");
return true;
}
return false;
}
private function getOptionValue(string $option, InputInterface $input): int
{
if ($input->getOption($option) !== false) {
return $input->getOption($option) ?? 1;
}
$optionKey = 'WORKER_' . strtoupper($option);
return $_SERVER[$optionKey];
}
}

View File

@@ -0,0 +1,10 @@
[program:torsearch-worker]
command=/app/bin/console messenger:consume async -vv --time-limit 3600
numprocs={{ replicas|default(1) }}
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d

View File

@@ -0,0 +1,10 @@
[program:torsearch-downloader]
command=/app/bin/console messenger:consume download -vv --time-limit 3600
numprocs={{ replicas|default(1) }}
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d

View File

@@ -0,0 +1,10 @@
[program:torsearch-scheduler]
command=/app/bin/console messenger:consume scheduler_monitor monitor -vv --time-limit 21600
numprocs={{ replicas|default(1) }}
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=3
process_name=%(program_name)s_%(process_num)02d

View File

@@ -0,0 +1,5 @@
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid