Ubuntu 20.04에서 Crontab을 사용하여 1분 동안 PHP 작업을 여러 번 실행하는 방법

Ubuntu 20.04에서 Crontab을 사용하여 1분 동안 PHP 작업을 여러 번 실행하는 방법

2022-06-01 last update

36 minutes reading PHP Ubuntu 20.04 LAMP Stack MySQL
저자는 Girls Who Code 계획의 일부로 기부를 받기로 했다.

소개


Linux에서는 특정 시간에 백그라운드에서 장시간 실행되는 작업을 다기능 Write for DOnations 으로 처리할 수 있습니다.수호 프로세스는 중복된 작업을 실행하기에 매우 적합하지만, 1분의 최소 시간 간격으로만 작업을 수행할 수 있습니다.
그러나 많은 응용 프로그램에서 나쁜 사용자 체험을 피하기 위해서는 더 자주 작업을 수행하는 것이 좋다.예를 들어 만약에 crontab tool 계획 사이트의 파일 처리 작업을 사용하고 있다면 대량의 기다림은 최종 사용자에게 부정적인 영향을 미칠 것이다.
또 다른 장면은 하나의 응용 프로그램으로 이 응용 프로그램은 작업 대기열 모델을 사용하여 클라이언트가 응용 프로그램의 특정 작업을 완성한 후 (예를 들어 수신자에게 송금) 클라이언트에게 텍스트 메시지나 이메일을 보낸다.만약 사용자가 확인 메시지를 전달하기 전에 1분을 기다려야 한다면, 그들은 업무가 실패했다고 생각하고 같은 업무를 반복하려고 시도할 수도 있다.
이러한 도전을 극복하기 위해 PHP 스크립트를 작성할 수 있습니다.crontab 수호 프로그램이 1분 후에 다시 호출될 때 반복해서 작업을 60초 동안 처리할 수 있습니다.crontab 데몬이 PHP 스크립트를 처음 호출하면 응용 프로그램 논리와 일치하는 시간 내에 작업을 수행할 수 있습니다. 사용자가 기다리지 않아도 됩니다.
이 안내서에서 Ubuntu 20.04 서버에 예시 cron_jobs 데이터베이스를 만듭니다.그런 다음 PHPtasks 순환과 while(...){...} 함수를 사용하여 5초 간격으로 테이블의 작업을 수행하는 sleep() 테이블과 스크립트를 설정합니다.

선결 조건


이 강좌를 완성하려면 다음과 같은 내용이 필요합니다.

  • 루트 사용자 설정이 아닌 Ubuntu 20.04 서버를 사용합니다.우리의 job-queue model 지침을 따르십시오.

  • 서버에 설치된 램프 스택입니다.Initial Server Setup with Ubuntu 20.04 안내서를 참조하십시오.이 강좌의 경우 4 단계를 건너뛰고 웹 사이트에 가상 호스트를 만들 수 있습니다.
  • 1단계 - 데이터베이스 설정


    이 단계에서, 예시 데이터베이스와 테이블을 만들 것입니다.먼저 SSH 서버에서 루트 사용자로 MySQL에 로그인합니다.
    1. sudo mysql -u root -p
    ySQL 서버의 루트 암호를 입력하고 ENTER 를 눌러 계속합니다.그리고 다음 명령을 실행하여 데이터베이스 cron_jobs 를 만듭니다.
    1. CREATE DATABASE cron_jobs;
    데이터베이스에 비root 사용자를 만듭니다.PHP에서 cron_jobs 데이터베이스에 연결하려면 사용자의 자격 증명이 필요합니다.강한값으로 바꾸기 EXAMPLE_PASSWORD:
    1. CREATE USER 'cron_jobs_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'EXAMPLE_PASSWORD';
    2. GRANT ALL PRIVILEGES ON cron_jobs.* TO 'cron_jobs_user'@'localhost';
    3. FLUSH PRIVILEGES;
    다음은 cron_jobs 데이터베이스로 전환합니다.
    1. USE cron_jobs;
    Output
    Database changed
    데이터베이스를 선택한 후 tasks 테이블을 만듭니다.이 테이블에서cron 작업으로 자동으로 실행될 작업을 삽입합니다.cron 작업을 실행하는 최소 시간 간격이 1분이기 때문에 나중에 이 설정을 덮어쓰는 PHP 스크립트를 작성하고 5초 간격으로 작업을 수행합니다.
    이제 tasks 테이블을 만듭니다.
    1. CREATE TABLE tasks (
    2. task_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    3. task_name VARCHAR(50),
    4. queued_at DATETIME,
    5. completed_at DATETIME,
    6. is_processed CHAR(1)
    7. ) ENGINE = InnoDB;
    tasks 테이블에 세 개의 기록을 삽입합니다.NOW() 열의 MySQLqueued_at 함수를 사용하여 작업 대기열의 현재 날짜와 시간을 기록합니다.completed_at 열의 경우 MySQLCURDATE() 함수를 사용하여 기본 시간을 00:00:00 로 설정할 수도 있습니다.나중에 작업이 완료되면 스크립트가 이 열을 업데이트합니다.
    1. INSERT INTO tasks (task_name, queued_at, completed_at, is_processed) VALUES ('TASK 1', NOW(), CURDATE(), 'N');
    2. INSERT INTO tasks (task_name, queued_at, completed_at, is_processed) VALUES ('TASK 2', NOW(), CURDATE(), 'N');
    3. INSERT INTO tasks (task_name, queued_at, completed_at, is_processed) VALUES ('TASK 3', NOW(), CURDATE(), 'N');
    INSERT 명령을 실행한 후 출력을 확인합니다.
    Output
    Query OK, 1 row affected (0.00 sec) ...
    SELECT 테이블의 실행tasks 문구를 통해 데이터를 확보합니다.
    1. SELECT task_id, task_name, queued_at, completed_at, is_processed FROM tasks;
    모든 작업 목록을 찾습니다.
    Output
    +---------+-----------+---------------------+---------------------+--------------+ | task_id | task_name | queued_at | completed_at | is_processed | +---------+-----------+---------------------+---------------------+--------------+ | 1 | TASK 1 | 2021-03-06 06:27:19 | 2021-03-06 00:00:00 | N | | 2 | TASK 2 | 2021-03-06 06:27:28 | 2021-03-06 00:00:00 | N | | 3 | TASK 3 | 2021-03-06 06:27:36 | 2021-03-06 00:00:00 | N | +---------+-----------+---------------------+---------------------+--------------+ 3 rows in set (0.00 sec)
    completed_at 열의 시간은 00:00:00 로 설정됩니다. 이 열은 다음 단계에서 만든 PHP 스크립트가 처리된 후에 업데이트됩니다.
    ySQL 명령줄 인터페이스를 종료하려면 다음과 같이 하십시오.
    1. QUIT;
    Output
    Bye
    cron_jobs 데이터베이스와 tasks 데이터베이스는 이미 준비가 되었음을 나타냅니다. 작업을 처리하는 PHP 스크립트를 만들 수 있습니다.

    2단계 - 5초 후에 작업을 실행하는 PHP 스크립트 만들기


    이 단계에서 PHPwhile(...){...} 순환과 sleep 함수의 조합을 사용하여 5초마다 작업을 실행하는 스크립트를 만들 것입니다.
    nano를 사용하여 웹 서버의 루트 디렉터리에서 새 /var/www/html/tasks.php 파일을 엽니다.
    1. sudo nano /var/www/html/tasks.php
    다음은 try { 표시 후 새 <?php 블록을 만들고 1단계에서 생성된 데이터베이스 변수를 설명합니다.데이터베이스 사용자의 실제 암호로 바꾸는 것을 기억하십시오EXAMPLE_PASSWORD:
    /var/www/html/tasks.php
    <?php
    try {
        $db_name     = 'cron_jobs';
        $db_user     = 'cron_jobs_user';
        $db_password = 'EXAMPLE_PASSWORD';
        $db_host     = 'localhost';
    
    다음은 새 PDO(PHP 데이터 객체) 클래스를 선언하고 속성ERRMODE_EXCEPTION을 설정하여 PDO 오류를 포착합니다.또한 ATTR_EMULATE_PREPARESfalse 로 전환하여 이 컴퓨터의 MySQL 데이터베이스 엔진이 시뮬레이션을 처리하도록 합니다.준비된 문구를 사용하면 SQL 쿼리와 데이터를 각각 전송하여 보안을 강화하고 SQL 주입 공격의 기회를 줄일 수 있습니다.
    /var/www/html/tasks.php
    
        $pdo = new PDO('mysql:host=' . $db_host . '; dbname=' . $db_name, $db_user, $db_password);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
        $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);       
    
    그런 다음 $loop_expiry_time 이라는 새 변수를 만들고 현재 시간으로 60초 설정합니다.그런 다음 새 PHPwhile(time() < $loop_expiry_time) { 문을 엽니다.현재 시간(time()이 변수$loop_expiry_time와 일치할 때까지 순환을 만드는 것이 좋습니다.
    [label /var/www/html/tasks.php]       
    
        $loop_expiry_time = time() + 60;
    
        while (time() < $loop_expiry_time) { 
    
    다음은 tasks 테이블에서 처리되지 않은 작업을 읽어들이는 준비된 SQL 문장을 설명합니다.
    [label /var/www/html/tasks.php]   
    
            $data = [];
            $sql  = "select 
                     task_id
                     from tasks
                     where is_processed = :is_processed
                     ";
    
    SQL 명령을 실행하고 tasks 테이블에서 열 is_processedN 의 모든 행으로 설정합니다.이것은 줄을 처리하지 않는다는 것을 의미한다.
    [label /var/www/html/tasks.php]  
    
            $data['is_processed'] = 'N';  
    
            $stmt = $pdo->prepare($sql);
            $stmt->execute($data);
    
    그런 다음 PHPwhile ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {...} 문을 사용하여 검색된 행을 순환하고 다른 SQL 문을 생성합니다.이번에 SQL 명령은 처리된 각 작업is_processedcompleted_at 열을 업데이트합니다.이렇게 하면 작업을 여러 번 처리하지 않을 수 있습니다.
    [label /var/www/html/tasks.php]  
    
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
                $data_update   = [];         
                $sql_update    = "update tasks set 
                                  is_processed  = :is_processed,
                                  completed_at  = :completed_at
                                  where task_id = :task_id                                 
                                  ";
    
                $data_update   = [		          
                                 'is_processed' => 'Y',                          
                                 'completed_at' => date("Y-m-d H:i:s"),
                                 'task_id'      => $row['task_id']                         
                                 ];
                $stmt = $pdo->prepare($sql_update);
                $stmt->execute($data_update);
            }
    
    주의: 처리할 대기열이 매우 크면(예를 들어 초당 100000개의 기록), How To Install Linux, Apache, MySQL, PHP (LAMP) stack on Ubuntu 20.04 작업 대기열 모델을 실현할 때 MySQL보다 빠르기 때문에 Redis Server 작업 대기열을 고려할 수 있습니다.그러나 이 안내서는 비교적 작은 데이터 집합을 처리할 것이다.
    첫 번째 PHPwhile (time() < $loop_expiry_time) { 문을 닫기 전에 작업을 5초 동안 중단하고 서버 자원을 방출하기 위해 sleep(5); 문을 포함하십시오.
    업무 논리와 작업 수행 속도에 따라 5초 주기를 변경할 수 있습니다.예를 들어, 작업을 1분에 3번 처리하려면 이 값을 20초로 설정합니다.catch 블록 내의 PDO 오류 메시지를 기억하십시오.
    [label /var/www/html/tasks.php]         
            sleep(5); 
    
            }       
    		
    } catch (PDOException $ex) {
        echo $ex->getMessage(); 
    }
    
    전체 } catch (PDOException $ex) { echo $ex->getMessage(); } 파일은 다음과 같습니다.
    /var/www/html/tasks.php
    <?php
    try {
        $db_name     = 'cron_jobs';
        $db_user     = 'cron_jobs_user';
        $db_password = 'EXAMPLE_PASSWORD';
        $db_host     = 'localhost';
    
        $pdo = new PDO('mysql:host=' . $db_host . '; dbname=' . $db_name, $db_user, $db_password);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
        $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);               
    
        $loop_expiry_time = time() + 60;
    
        while (time() < $loop_expiry_time) { 
            $data = [];
            $sql  = "select 
                     task_id
                     from tasks
                     where is_processed = :is_processed
                     ";
    
            $data['is_processed'] = 'N';             
    
            $stmt = $pdo->prepare($sql);
            $stmt->execute($data);
    
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { 
                $data_update   = [];         
                $sql_update    = "update tasks set 
                                  is_processed  = :is_processed,
                                  completed_at  = :completed_at
                                  where task_id = :task_id                                 
                                  ";
    
                $data_update   = [		          
                                 'is_processed' => 'Y',                          
                                 'completed_at' => date("Y-m-d H:i:s"),
                                 'task_id'      => $row['task_id']                         
                                 ];
                $stmt = $pdo->prepare($sql_update);
                $stmt->execute($data_update);
            }   
           
            sleep(5); 
    
            }       
    		
    } catch (PDOException $ex) {
        echo $ex->getMessage(); 
    }
    
    tasks.php+CTRL,X을 누르고 Y를 눌러 파일을 저장합니다.ENTER 파일의 논리적 인코딩을 완료하면crontab 수호 프로그램이 다음 단계에서 1분마다 이 파일을 실행하도록 설정합니다.

    3단계 - 1분 후에 PHP 스크립트 실행 계획


    Linux에서crontab 파일에 명령을 입력하면 작업이 정해진 시간 후에 자동으로 실행되도록 설정할 수 있습니다.이 단계에서,crontab 수호 프로그램이 분당 /var/www/html/tasks.php 스크립트를 실행하도록 지시합니다.따라서 nano를 사용하여 /var/www/html/tasks.php 파일을 엽니다.
    1. sudo nano /etc/crontab
    그리고 파일 끝에 다음과 같은 내용을 추가하여 /etc/crontab분 후에 실행합니다http://localhost/tasks.php.
    /etc/crontab
    ...
    * * * * * root /usr/bin/wget -O - http://localhost/tasks.php
    
    파일을 저장하고 닫습니다.
    이 안내서는cron 작업의 작업 방식에 대해 기본적으로 알고 있다고 가정합니다.읽기How to Use Cron to Automate Tasks on Ubuntu의 지침을 고려하다.
    앞에서 말한 바와 같이,cron 수호 프로그램은 1분에 한 번 1 파일을 실행하지만, 파일이 처음 실행되면, 열린 작업에서 60초 동안 순환합니다.순환 시간이 만료되면cron 수호 프로그램은 이 파일을 다시 실행하고, 이 과정은 계속될 것입니다.tasks.php 파일을 업데이트하고 닫은 후,crontab 수호 프로그램은 삽입 /etc/crontab 표의 MySQL 작업을 즉시 시작해야 합니다.모든 것이 예상대로 작동하는지 확인하기 위해 데이터베이스tasks를 조회합니다.

    단계 4 - 작업 수행 확인


    이 단계에서, cron_jobs 파일이crontab에서 자동으로 실행될 때 줄 서기 작업을 처리하고 있는지 확인하기 위해 데이터베이스를 다시 열 것입니다.
    루트 사용자로 MySQL 서버에 다시 로그인하려면 다음과 같이 하십시오.
    1. sudo mysql -u root -p
    그런 다음 MySQL 서버의 루트 암호를 입력하고 tasks.php 를 클릭하여 계속합니다.그런 다음 데이터베이스로 전환합니다.
    1. USE cron_jobs;
    Output
    Database changed
    ENTER 테이블 실행 SELECT 문구:
    SELECT task_id, task_name, queued_at, completed_at, is_processed FROM tasks;
    
    다음과 같은 출력을 받을 수 있습니다.tasks 열에서 completed_at초마다 작업을 처리합니다.또한 5 열이 is_processed, 즉 Y 으로 설정되어 작업이 완료된 것으로 표시됩니다.
    Output
    +---------+-----------+---------------------+---------------------+--------------+ | task_id | task_name | queued_at | completed_at | is_processed | +---------+-----------+---------------------+---------------------+--------------+ | 1 | TASK 1 | 2021-03-06 06:27:19 | 2021-03-06 06:30:01 | Y | | 2 | TASK 2 | 2021-03-06 06:27:28 | 2021-03-06 06:30:06 | Y | | 3 | TASK 3 | 2021-03-06 06:27:36 | 2021-03-06 06:30:11 | Y | +---------+-----------+---------------------+---------------------+--------------+ 3 rows in set (0.00 sec)
    이것은 PHP 스크립트가 예상대로 작동하는지 확인합니다.crontab 수호 프로그램이 설정한 1분 시간 제한을 덮어쓰면 더 짧은 시간 간격으로 작업을 실행할 수 있습니다.

    결론


    이 안내서에서 Ubuntu 20.04 서버에 예시 데이터베이스를 설정했습니다.그런 다음 테이블에서 작업을 만들고 PHPYES 순환 및 while(...){...} 함수를 사용하여 5초마다 실행합니다.다음에 작업 대기열 기반 프로그램을 실행할 때 작업이 1분 안에 여러 번 실행되어야 한다면 이 강좌의 논리를 사용하십시오.
    자세한 PHP 자습서는 Dell의 PHP topic page 을 참조하십시오.