"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > Supervisor를 사용하여 Symfony 명령 실행 처리

Supervisor를 사용하여 Symfony 명령 실행 처리

2024-11-01에 게시됨
검색:896

소개

이 게시물에서 우리는 감독자를 사용하여 심포니 명령 실행을 처리하는 방법을 배울 것입니다. 기본적으로 Supervisord는 다음을 허용합니다:

  • 명령 자동 시작
  • 명령 자동 다시 시작
  • 감독자가 시작할 프로세스 수를 지정합니다.

문제

때때로 우리는 프로세스 실행을 자동화하기 위해 unix crontab을 사용합니다. 이 방법은 대부분의 경우 작동하지만 문제가 발생할 수 있는 상황이 있을 수 있습니다.

사용자의 알림을 기록하는 데이터베이스 테이블이 있다고 가정해 보겠습니다. 테이블에는 다음 정보가 저장됩니다.

  • 사용자
  • 텍스트
  • 채널
  • 상태(대기 중, 전송됨)
  • 작성일자
  • 업데이트 날짜

반면에 다음 단계에 따라 실행되는 명령을 코딩했습니다.

  • 마지막 WAITING 알림을 쿼리합니다.
  • 쿼리된 알림을 반복하고 다음을 수행합니다.
    • 해당 사용자에게 각각 전송합니다.
    • 알림 상태를 대기 중에서 전송됨으로 업데이트합니다.

Linux crontab에서 이 명령이 자주(1분, 2분 등) 실행되도록 설정했습니다. 지금까지는 아주 좋습니다.

이제 현재 프로세스가 500개의 알림을 쿼리했고 400개를 보냈을 때 새 프로세스가 시작된다고 가정해 보겠습니다. 이는 새 프로세스가 마지막 프로세스와 새 프로세스에 의해 아직 업데이트되지 않은 100개의 알림을 쿼리한다는 것을 의미합니다.

Using Supervisor to handle a Symfony Command execution

두 프로세스가 모두 쿼리했기 때문에 100개의 알림이 두 번 전송될 수 있습니다.

해결책

해결책으로 감독자를 사용할 수 있습니다. 프로세스를 계속 실행하고 필요할 때 다시 시작합니다. 이렇게 하면 하나의 프로세스만 유지하고 중복을 피할 수 있습니다. 명령이 어떻게 보이는지 분석해 보겠습니다.

#[AsCommand(
    name: 'app:notification'
)]
class NotificationCommand extends Command
{
    private bool $forceFinish = false;

    protected function configure(): void
    {
        $this
            ->addOption('time-limit', null, InputOption::VALUE_OPTIONAL, 'Max time alive in seconds')
            ->addOption('time-between-calls', null, InputOption::VALUE_OPTIONAL, 'Time between every loop call')

        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->forceFinish = false;
        pcntl_signal(SIGTERM, [$this, 'signalHandler']);
        pcntl_signal(SIGINT, [$this, 'signalHandler']);

        $timeLimit = $input->getOption('time-limit');
        $timeBetweenCalls = $input->getOption('time-between-calls');
        $dtMax = (new \DateTimeImmutable())->add(\DateInterval::createFromDateString("  {$timeLimit} seconds"));

        do{
           // Here we should execute a service to query and send notifications
           // ......

           sleep($timeBetweenCalls);
           $dtCurrent = new \DateTimeImmutable();

        }while($dtCurrent forceFinish);

        return Command::SUCCESS;
    }

    public function signalHandler(int $signalNumber): void
    {
        echo 'Signal catch: ' . $signalNumber . PHP_EOL;
        match ($signalNumber) {
            SIGTERM, SIGINT => $this->forceFinish = true,
            default => null
        };
    }
}

명령어를 단계별로 설명하겠습니다.

  • configure 메소드는 입력 옵션을 선언합니다:

    • time-limit: 명령 프로세스가 활성화될 수 있는 최대 시간입니다. 그 후에는 작업이 완료되고 감독자가 다시 시작합니다.
    • time-between-calls: 각 루프 반복 후 잠자기 시간입니다. 루프는 알림을 처리한 다음 해당 시간 동안 휴면하는 서비스를 호출합니다.
  • execute 메소드는 다음과 같이 동작합니다:

    • forceFinish 클래스 변수를 true로 설정합니다.
    • PHP pnctl 라이브러리를 사용하여 Unix SIGTERMSIGINT 신호를 처리하기 위한 signalHandler 메소드를 등록합니다.
    • 입력 옵션 값을 가져오고 시간 제한 옵션 값을 사용할 때까지 명령이 활성화될 수 있는 최대 날짜를 계산합니다.
    • do-while 루프는 알림을 받고 보내는 데 필요한 코드를 수행합니다(명령에 배치되지 않고 대신 주석이 있습니다). 그런 다음 계속하기 전에 통화 간 시간 옵션으로 설정된 시간 동안 절전 모드로 전환됩니다.
    • 현재 날짜(루프 반복마다 계산됨)가 최대 날짜보다 낮고 forceFinish가 false인 경우 루프가 계속됩니다. 그렇지 않으면 명령이 종료됩니다.
  • signalHandler 함수는 SIGTERM 및 SIGINT Unix 신호를 포착합니다. SIGINT는 Ctrl C를 누를 때 전송되는 신호이고 SIGTERM은 kill 명령을 사용할 때 기본 신호입니다. signalHandler 함수가 이를 감지하면 forceFinish 변수를 true로 설정하여 현재 루프가 끝나면 forceFinish 변수가 종료되므로 명령이 종료됩니다. 더 이상 거짓이 아닙니다. 이를 통해 사용자는 최대 날짜가 완료될 때까지 기다리지 않고 프로세스를 종료할 수 있습니다.

감독자 구성

지금까지 명령이 생성되었습니다. 이제 이를 처리할 수 있도록 감독자를 설정해야 합니다. 구성을 시작하기 전에 감독자를 설치해야 합니다. 다음 명령을 실행하여 수행할 수 있습니다.

sudo apt update && sudo apt install supervisor

설치 후 다음 명령을 실행하여 감독자가 실행되고 있는지 확인할 수 있습니다.

sudo systemctl status supervisor

감독자 구성 파일은 /etc/supervisor/conf.d 폴더에 있습니다. notif.conf라는 파일을 만들고 다음 내용을 붙여넣습니다.

command=php /bin/console app:notifications --time-limit=120 --time-between-calls=10
user=
numprocs=1
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d

각 키를 설명해 보겠습니다.

  • 명령: 시작 명령
  • 사용자: 명령을 실행하는 Unix 사용자
  • numprocs: 실행할 프로세스 수
  • autostart: 명령을 자동 시작할지 여부
  • autostart: 명령을 자동으로 다시 시작할지 여부
  • 프로세스_이름: Unix 프로세스 이름 형식 명령입니다.

이 구성을 사용하면 app:notifications 명령이 최대 120초 동안 실행되며 매 루프 후 10초 동안 절전 모드로 전환됩니다. 120초가 경과하거나 Unix 신호를 캐싱한 후 명령은 루프를 종료하고 완료됩니다. 그런 다음 감독자가 다시 시작합니다.

결론

우리는 crontab을 사용하지 않고도 감독자를 사용하여 명령을 계속 실행하는 방법을 배웠습니다. 이는 crontab에 의해 시작된 프로세스가 중복되어 데이터 손상을 일으킬 수 있는 경우 유용할 수 있습니다.

내가 쓴 마지막 책에서 나는 관리자를 사용하여 심포니 메신저 워커를 계속 실행하는 방법을 보여주었습니다. 더 알고 싶다면 여기에서 책을 찾을 수 있습니다: PHP 및 Symfony 프레임워크를 사용하여 작업 지향 API 구축: 단계별 가이드

릴리스 선언문 이 글은 https://dev.to/icolomina/using-supervisor-to-handle-a-symfony-command-execution-41h7?1에서 복제됩니다.1 침해 내용이 있는 경우, [email protected]으로 연락하여 삭제하시기 바랍니다. 그것
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3