Implement Timer tasks (timer) in PHP only, and implement Timer timer in php

Source: Internet
Author: User

Implement Timer tasks (timer) in PHP only, and implement Timer timer in php

Timer tasks are common in WEB applications. There are roughly two ways to implement Timer tasks using PHP: 1) Use the Crontab command to write a shell script and call the PHP file in the script, then execute the script regularly; 2) use ignore_user_abort () and set_time_limit () to run the script out of the browser. The former uses the features of Linux and does not have much to do with PHP itself. The latter has limited use cases and can only trigger the script once in an HTTP request. After the script is executed, it exits. So how can we use pure PHP to implement pure timer tasks and meet the business needs of task recognition?

Basic knowledge

This program is developed in Linux and runs in cli mode. Here is a brief introduction to basic knowledge.

  • CLI: PHP Command Line Mode. Common WEB applications use fpm;
  • Processes: processes are the basic unit for running programs. They run independently and do not interfere with each other. They have independent runtime spaces and each process has a process control block;
  • Inter-process communication: Since processes run independently, we need a mechanism to ensure information exchange between different processes. inter-process communication mainly includes: pipelines, IPC (shared memory,Signal, Message Queue), socket;
  • PCNTL Extension: A process extension of PHP. It mainly uses the pcntl_alarm () function. For details, refer to the official website.

Implementation Principle    

Use a three-dimensional array to save all the tasks to be executed. The first-level index is the timestamp, the value is the method for executing the task, and the callback parameters. The specific array format is as follows:

 

Array ('20140901' => array (1, array ('class', 'func'), array (), true),) Description: 1438156396 timestamp array (1, array ('class', 'func'), array (), true) parameters are represented in sequence: Execution interval, callback function, whether the parameter passed to the callback function is persistent (true is always stored in the data; otherwise, it is deleted after execution)

 

These tasks can be methods of any class. Since it is a scheduled task, we need something similar to timing. This solution uses semaphores to send SIGALRM signals to the current process every second, capture the signals, and trigger the signal processing function, traverse data cyclically to determine whether there are tasks to be executed at the current time. If yes, the callback method is used and the parameter is passed to the method.

1 <? Php 2/** 3 * Timer 4 */5 class Timer 6 {7 // save all scheduled tasks 8 public static $ task = array (); 9 10 // regular interval 11 public static $ time = 1; 12 13/** 14 * Start Service 15 * @ param $ time int 16 */17 public static function run ($ time = null) 18 {19 if ($ time) 20 {21 self ::$ time = $ time; 22} 23 self: installHandler (); 24 pcntl_alarm (1 ); 25} 26/** 27 * register the signal processing function 28 */29 public static function installHandler () 30 {31 pcntl_signal (SIGALRM, array ('timer ', 'signatalhandler'); 32} 33 34/** 35 * signal processing function 36 */37 public static function signalHandler () 38 {39 self: task (); 40 // after a signal event is executed, the next 41 pcntl_alarm (self: $ time) is triggered ); 42} 43 44/** 45 * execution callback 46 */47 public static function task () 48 {49 if (empty (self: $ task )) 50 {// no task, 51 return; 52} 53 foreach (self ::$ task as $ time => $ arr) 54 {55 $ current = time (); 56 57 foreach ($ arr as $ k => $ job) 58 {// traverse every task 59 $ func = $ job ['func']; /* callback function */60 $ argv = $ job ['argv'];/* callback function parameter */61 $ interval = $ job ['interval']; /* time Interval */62 $ persist = $ job ['persist'];/* persistence */63 64 if ($ current = $ time) 65 {// The current time has executed task 66 67 // call the callback function and pass the parameter 68 call_user_func_array ($ func, $ argv ); 69 70 // Delete this task 71 unset (self: $ task [$ time] [$ k]); 72} 73 if ($ persist) 74 {// If persistence is performed, write the array and wait for 75 self ::$ task [$ current + $ interval] [] = $ job; 76} 77} 78 if (empty (self: $ task [$ time]) 79 {80 unset (self: $ task [$ time]); 81} 82} 83} 84 85/** 86 * add task 87 */88 public static function add ($ interval, $ func, $ argv = array (), $ persist = false) 89 {90 if (is_null ($ interval) 91 {92 return; 93} 94 $ time = time () + $ interval; 95 // write scheduled task 96 self: $ task [$ time] [] = array ('func' => $ func, 'argv' => $ argv, 'interval' => $ interval, 'persist' => $ persist); 97} 98 99/** 100 * Delete all timer tasks 101 */102 public function dellAll () 103 {104 self ::$ task = array (); 105} 106}

This is the core part of the Timer class. There is a static variable that stores all the tasks to be executed. Why is it static here? Think for yourself. when the process receives the SIGALRM signal, it triggers the signalHandler function, and then traverses the array sequentially to check whether there are tasks to be executed at the current time. If yes, it calls back and Passes parameters to delete the current job, then, check whether the persistence task is to be performed. If yes, continue to write the current job into the event array and wait for the next trigger. Finally, set an alarm signal for the current process. it can be seen that this timer will be triggered again from the Internal as long as it is triggered once to get the self-loop purpose.

 1 <?php 2  3 class DoJob 4 { 5     public function job( $param = array() ) 6     { 7         $time = time(); 8         echo "Time: {$time}, Func: ".get_class()."::".__FUNCTION__."(".json_encode($param).")\n"; 9     }10 }

This is a callback class and function. For convenience, we have added a lot of debugging information. Timer classes and Callbacks are available. Let's take a look at the usage scenarios.

 1 <?php 2  3 require_once(__DIR__."/Timer.php"); 4 require_once(__DIR__."/DoJob.php"); 5  6  7 Timer::dellAll(); 8  9 Timer::add( 1, array('DoJob','job'), array(),true);10 11 Timer::add( 3, array('DoJob','job'),array('a'=>1), false);12 13 echo "Time start: ".time()."\n";14 Timer::run();15 16 while(1)17 {18     sleep(1);19     pcntl_signal_dispatch();20 }

The code is very short. Here two jobs are registered, and then the timer is run, in an infiniteCapture signals in a loopIf not captured, the pre-registered handler function cannot be triggered. The self-loop timer is developed successfully. The running result is as follows:

  

Like the tasks added in our scenario class, two tasks were executed at 90, one for a persistent job without parameters and the other for a non-persistent job with parameters, then the non-persistent job is not executed.

Summary

  • The current process cannot exit before receiving the signal. here I use a true loop with the condition always. in our actual production environment, we need to create such a prerequisite. For example, we have a group of services that are always running, regardless of IO access, waiting for socket links, etc, the current service will not be terminated, even if the process is blocked, there will be no problem. In this scenario, it is used in a continuously running service.
  • Currently, PHP only supports triggering in seconds. It does not support smaller time units. It is basically enough for scheduled tasks.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.