Skip to content

Commit

Permalink
chore(sigterm): amélioration de la gestion des SIGTERM (#60)
Browse files Browse the repository at this point in the history
* chore(sigterm): forward SIGTERM to apache2 server (refs #59)

* chore(sigterm): improve SIGTERM handling in loop-validate.sh to exit nicely and restart current validation (refs #59)

* fix(sigterm): remove sleep added for debug purpose (refs #59)

* fix(sigterm): add missing exec in application.sh and missing extension pcntl in docker image (refs #59)

---------

Co-authored-by: Sylvain Lafay <sylvain.lafay@ign.fr>
  • Loading branch information
mborne and slafayIGN authored Dec 8, 2023
1 parent 3cc8204 commit 5c2f2b3
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 12 deletions.
4 changes: 2 additions & 2 deletions .docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ FROM composer:2.3 as vendor
RUN mkdir -p /opt/validator-api
WORKDIR /opt/validator-api
COPY composer.json .
RUN composer install --no-scripts --prefer-dist
RUN composer install --no-scripts --prefer-dist --ignore-platform-req=ext-pcntl

#----------------------------------------------------------------------
# Create base layer for dev and production
Expand Down Expand Up @@ -49,7 +49,7 @@ COPY .docker/php.ini /usr/local/etc/php/conf.d/app.ini
RUN apt-get update -qq \
&& apt-get install -y postgresql-client libpq-dev libzip-dev \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install opcache pdo pdo_pgsql pgsql zip \
&& docker-php-ext-install opcache pdo pdo_pgsql pgsql zip pcntl \
&& rm -rf /var/lib/apt/lists/*

#----------------------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions .docker/application.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ run(){
fi

#---------------------------------------------------------------------------
# start apache as www-data
# start apache2 server
#---------------------------------------------------------------------------
/usr/sbin/apachectl -D FOREGROUND
exec apache2-foreground
}

backend(){
bash loop-validate.sh
exec bash loop-validate.sh
}

test(){
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"ext-ctype": "*",
"ext-iconv": "*",
"ext-zip": "*",
"ext-pcntl": "*",
"composer/package-versions-deprecated": "^1.11",
"doctrine/annotations": "^1.10",
"doctrine/doctrine-bundle": "^2.1",
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ services:
#-----------------------------------------------------------------------
backend:
image: ignf/validator-api:master-dev
command: .docker/application.sh backend
command: [".docker/application.sh","backend"]
environment:
- HTTP_PROXY=${HTTP_PROXY}
- HTTPS_PROXY=${HTTPS_PROXY}
Expand Down
37 changes: 33 additions & 4 deletions loop-validate.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
#!/bin/bash
set -e

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

while true
RUNNING=1

_term(){
echo "$BASH_SOURCE - caught signal, terminating..."
RUNNING=0
kill -s SIGTERM $child_pid
wait
}


# Note that trapping SIGWINCH is due to weird usage of this "window resized" by apache2
# (see https://bz.apache.org/bugzilla/show_bug.cgi?id=50669)
# ...propagated to STOPSIGNAL=SIGWINCH in php:8.2-apache docker image
# ...which leads to an unexpected behavior of "docker stop"
# ...and probably problems with PHP applications including console commands (Symfony, Laravel,...)
trap _term SIGTERM SIGINT SIGWINCH

echo "$BASH_SOURCE - started with PID=$$"

while [ $RUNNING -eq 1 ]
do
php "${SCRIPT_DIR}/bin/console" ign-validator:validations:process-one -vv
sleep 15
php "${SCRIPT_DIR}/bin/console" ign-validator:validations:process-one -vvv &
child_pid=$!
wait $child_pid

if [ $RUNNING -eq 0 ];
then
break;
fi

sleep 15 &
child_pid=$!
wait $child_pid
done

echo "$BASH_SOURCE - stopped"
30 changes: 28 additions & 2 deletions src/Command/Validations/ProcessOneCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
namespace App\Command\Validations;

use App\Validation\ValidationManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Command\SignalableCommandInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Helper command to process pending validations.
*/
class ProcessOneCommand extends Command
class ProcessOneCommand extends Command implements SignalableCommandInterface
{
protected static $defaultName = 'ign-validator:validations:process-one';

Expand All @@ -19,8 +21,14 @@ class ProcessOneCommand extends Command
*/
private $validationManager;

/**
* @var LoggerInterface
*/
private $logger;

public function __construct(
ValidationManager $validationManager
ValidationManager $validationManager,
LoggerInterface $logger
) {
parent::__construct();
$this->validationManager = $validationManager;
Expand All @@ -43,4 +51,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int
return 0;
}

public function getSubscribedSignals(): array
{
return [\SIGINT,\SIGTERM];
}

public function handleSignal(int $signal): void
{
$this->logger->warning("[ProcessOneCommand] received stop signal while processing validation!",[
'signal' => $signal
]);
$this->validationManager->cancelProcessing();
$exitCode = 128 + $signal;
$this->logger->info("terminate process with exitCode={exitCode}",[
'exitCode' => $exitCode
]);
exit($exitCode);
}
}

26 changes: 26 additions & 0 deletions src/Validation/ValidationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ class ValidationManager
*/
private $zipArchiveValidator;

/**
* Current validation (in order to handle SIGTERM)
* @var Validation
*/
private $currentValidation = null;

public function __construct(
EntityManagerInterface $em,
ValidationsStorage $storage,
Expand Down Expand Up @@ -95,7 +101,27 @@ public function processOne()
$this->logger->debug("processOne : no validation pending, quitting");
return;
}
$this->currentValidation = $validation;
$this->doProcess($validation);
$this->currentValidation = null;
}

/**
* Stop currently running validation (invoked when SIGTERM is received)
*
* @return void
*/
public function cancelProcessing(){
if ( is_null($this->currentValidation) ){
$this->logger->debug("SIGTERM received, no validation in progress");
return ;
}
$this->logger->warning("Validation[{uid}]: SIGTERM received, changing state to pending",[
"uid" => $this->currentValidation->getUid()
]);
$this->currentValidation->setStatus(Validation::STATUS_PENDING);
$this->em->persist($this->currentValidation);
$this->em->flush();
}

/**
Expand Down

0 comments on commit 5c2f2b3

Please sign in to comment.