>  기사  >  백엔드 개발  >  Supervisor를 사용하여 Symfony 명령 실행 처리

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

WBOY
WBOY원래의
2024-09-07 06:34:021095검색

소개

이 게시물에서는 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 < $dtMax && !$this->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-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 <your_project_folder>/bin/console app:notifications --time-limit=120 --time-between-calls=10
user=<your_user>
numprocs=1
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d

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

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

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

결론

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

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

위 내용은 Supervisor를 사용하여 Symfony 명령 실행 처리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.