FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Worker.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi\Fred;
4 
5 class Worker extends Component{
6 
7  public $classNameAlias = []; //!< Job class name aliasses (key = alias, value = class name).
8  public $parallelCommand = null; //!< Command for executing a single job as a seperate process (asterisk is replaced with job
9  // ID, dollar sign with PHP binary path; empty = no parallel processing).
10  public $timeLimit = 60; //!< Default time limit for a job (seconds).
11  public $minTime = 10; //!< Keep processing for at least this amount of time (seconds; even when there are no more jobs
12  // scheduled).
13  public $sleepTime = 0.5; //!< Time to sleep when there are no more jobs scheduled (but still within minTime; seconds).
14  public $maxTime = 300; //!< Halt the processig of jobs after this time (seconds; even when there are more jobs scheduled).
15  public $maxJobs = 100; //!< Halt the processig of jobs after this amount of jobs processed (even when there are more jobs
16  // scheduled).
17  public $defaultOverduePeriod = '+1 hour'; //!< Default overdue period for jobs that do not have a rescheduling interval.
18  public $logTimerPrio = null; //!< Log the begin and end times of a job with this (custom) prio.
19 
20  /**
21  * Translate a job class name.
22  * @param string $class_name Class name for the job, or an alias.
23  * @return string Class name.
24  */
25  protected function transClassName($class_name){
26  return $this->classNameAlias[$class_name] ?? $class_name;
27  }
28  /**
29  * Add a job to the queue.
30  * @param string|array $class_name Class name for the job (or array with group code and class name).
31  * @param array $config Configuration options (key-value pairs) for the job.
32  * @param int $time Time to run the job (null for as soon as possible).
33  * @param string $interval String that is understood by PHP's strtotime() to reschedule the job after it is finished. Prefix
34  * with an '@' to make it relative to the time of finishing (normally it is relative to the planned time).
35  * @param int $max_time Maximum time for executing job (seconds).
36  * @return string Job ID when successful.
37  */
38  public function schedule($class_name,$config = null,$time = null,$interval = null,$max_time = null){
39  return false;
40  }
41  /**
42  * Delete a scheduled job from the queue.
43  * @param string $id Job ID.
44  * @return bool True when successful.
45  */
46  public function delete($id){
47  return false;
48  }
49  /**
50  * Create a job object.
51  * @param string $class_name Class name for the job.
52  * @param string $id Unique ID for the job.
53  * @param array $config Configuration options (key-value pairs) for the job.
54  * @param int $time Time to run the job (null for as soon as possible).
55  * @param string $interval String that is understood by PHP's strtotime() to reschedule the job after it is finished. Prefix
56  * with an '@' to make it relative to the time of finishing (normally it is relative to the planned time).
57  * @param int $max_time Maximum time for executing job (seconds).
58  * @return \\Rsi\\Fred\\Worker\\Job
59  */
60  protected function create($class_name,$id,$config = null,$time = null,$interval = null,$max_time = null){
61  return new $class_name($this,$id,$config,$time,$interval,$max_time);
62  }
63  /**
64  * Run a job instantly.
65  * @param string $class_name Class name for the job.
66  * @param array $config Configuration options (key-value pairs) for the job.
67  * @param string $timer_id Timer ID for the job to log to.
68  */
69  public function instant($class_name,$config = null,$timer_id = null){
70  $this->create($class_name,null,$config)->execute($timer_id);
71  }
72  /**
73  * Next scheduled job to execute.
74  * @param string $id Only check this job ID.
75  * @return \\Rsi\\Fred\\Worker\\Job (empty if there is no job to be executed).
76  */
77  protected function next($id = null){
78  return null;
79  }
80  /**
81  * Lock a job.
82  * @param \\Rsi\\Fred\\Worker\\Job $job Job to lock.
83  * @return bool True if the job has been locked.
84  */
85  protected function lock($job){
86  return false;
87  }
88  /**
89  * Unlock a job.
90  * @param \\Rsi\\Fred\\Worker\\Job $job Job to unlock.
91  * @return bool True if the job has been unlocked.
92  */
93  protected function unlock($job){
94  return true;
95  }
96  /**
97  * Reschedule a job.
98  * @param \\Rsi\\Fred\\Worker\\Job $job Job to reschedule.
99  * @param int $time Time to reschedule at (null for as soon as possible).
100  * @return bool True if the job has been rescheduled.
101  */
102  protected function reschedule($job,$time = null){
103  return false;
104  }
105  /**
106  * Mark a job as done.
107  * @param \\Rsi\\Fred\\Worker\\Job $job Job.
108  */
109  protected function ready($job){
110  $this->delete($job->id);
111  }
112  /**
113  * Number of active jobs in a group.
114  * @param int $group_id Group ID.
115  * @return int Number of active (locked) jobs.
116  */
117  protected function groupCount($group_id){
118  return 0;
119  }
120  /**
121  * Check if the group (if any) is within its limit.
122  * @param \\Rsi\\Fred\\Worker\\Job $job Job.
123  * @return bool True when OK.
124  */
125  protected function checkGroup($job){
126  return !$job->groupId || !$job->groupMaxCount || ($this->groupCount($job->groupId) < $job->groupMaxCount);
127  }
128  /**
129  * Overdue jobs.
130  * Jobs that have been locked longer than twice their interval or the default overdue interval.
131  * @return array Of \\Rsi\\Fred\\Worker\\Job items.
132  */
133  protected function overdue(){
134  return [];
135  }
136  /**
137  * Execute the worker / process the scheduled jobs.
138  * Call his function as often as possible.
139  * @param string $id Only check this job ID.
140  */
141  public function execute($id = null){
142  $log = $this->component('log');
143  $count = 0;
144  $start = time();
145  if($this->parallelCommand && !$id){
146  $done = [];
147  while(time() - $start <= $this->minTime){
148  if(($job = $this->next()) && (($done[$job->id] ?? -1) != $job->time) && $this->checkGroup($job)){
149  $command = strtr($this->parallelCommand,['*' => $job->id,'$' => escapeshellarg(PHP_BINARY)]);
150  $log->info("Executing job '{$job->id}' in parallel",__FILE__,__LINE__,compact('command'));
151  \Rsi::executeParallel($command);
152  if((++$count >= $this->maxJobs) || (time() - $start >= $this->maxTime)) break;
153  $done[$job->id] = $job->time;
154  }
155  else usleep($this->sleepTime * 1000000);
156  }
157  }
158  else do{
159  while(($job = $this->next($id)) && $this->checkGroup($job) && $this->lock($job)) try{
160  $this->_fred->timeLimit = $this->timeLimit;
161  $timer_id = $this->logTimerPrio ? $log->start($this->logTimerPrio,"Executing job '{$job->id}'",__FILE__,__LINE__) : null;
162  $job->execute($timer_id);
163  if($timer_id) $log->stop($timer_id);
164  if($job->interval){
165  $diff = ($time = $job->nextTime) - time();
166  if(!$time) $log->alert("Invalid interval for job '{$job->id}'",__FILE__,__LINE__);
167  elseif($diff < 0) $log->warning("Job '{$job->id}' rescheduled in past",['diff' => $diff]);
168  $this->reschedule($job,$time);
169  }
170  else $this->ready($job);
171  $this->unlock($job);
172  if((++$count >= $this->maxJobs) || (time() - $start >= $this->maxTime)) break;
173  }
174  catch(\Exception $e){
175  $log->critical($e);
176  }
177  usleep($this->sleepTime * 1000000);
178  }
179  while(!$id && (time() - $start <= $this->minTime));
180  foreach($this->overdue() as $job) $log->critical("Job '{$job->id}' is overdue",['time' => $job->time,'interval' => $job->interval]);
181  }
182 
183 }
Rsi\Fred\Worker\$classNameAlias
$classNameAlias
Job class name aliasses (key = alias, value = class name).
Definition: Worker.php:7
Rsi\Fred\Worker\next
next($id=null)
Next scheduled job to execute.
Definition: Worker.php:77
Rsi\Fred\Worker\$defaultOverduePeriod
$defaultOverduePeriod
Default overdue period for jobs that do not have a rescheduling interval.
Definition: Worker.php:17
Rsi\Fred\Worker\transClassName
transClassName($class_name)
Translate a job class name.
Definition: Worker.php:25
Rsi\Fred\Worker\instant
instant($class_name, $config=null, $timer_id=null)
Run a job instantly.
Definition: Worker.php:69
Rsi\Fred\Worker\$minTime
$minTime
Keep processing for at least this amount of time (seconds; even when there are no more jobs.
Definition: Worker.php:11
Rsi\Fred\Worker\checkGroup
checkGroup($job)
Check if the group (if any) is within its limit.
Definition: Worker.php:125
Rsi\Fred\Worker\$timeLimit
$timeLimit
Default time limit for a job (seconds).
Definition: Worker.php:10
Rsi\Fred\Worker\$logTimerPrio
$logTimerPrio
Log the begin and end times of a job with this (custom) prio.
Definition: Worker.php:18
Rsi\Fred\Worker\overdue
overdue()
Overdue jobs.
Definition: Worker.php:133
Rsi\Fred\Component
Basic component class.
Definition: Component.php:8
Rsi\Fred\Worker\schedule
schedule($class_name, $config=null, $time=null, $interval=null, $max_time=null)
Add a job to the queue.
Definition: Worker.php:38
Rsi\Fred\Worker
Definition: Worker.php:5
Rsi\Fred\Component\component
component($name)
Get a component (local or default).
Definition: Component.php:81
Rsi\Fred\Worker\$parallelCommand
$parallelCommand
Command for executing a single job as a seperate process (asterisk is replaced with job.
Definition: Worker.php:8
Rsi\Fred\Worker\$maxTime
$maxTime
Halt the processig of jobs after this time (seconds; even when there are more jobs scheduled).
Definition: Worker.php:14
Rsi\Fred\Worker\$maxJobs
$maxJobs
Halt the processig of jobs after this amount of jobs processed (even when there are more jobs.
Definition: Worker.php:15
Rsi\Fred\Worker\reschedule
reschedule($job, $time=null)
Reschedule a job.
Definition: Worker.php:102
Rsi\Fred\Worker\groupCount
groupCount($group_id)
Number of active jobs in a group.
Definition: Worker.php:117
Rsi\Fred\Worker\unlock
unlock($job)
Unlock a job.
Definition: Worker.php:93
Rsi\Fred\Worker\execute
execute($id=null)
Execute the worker / process the scheduled jobs.
Definition: Worker.php:141
Rsi\Fred\Worker\create
create($class_name, $id, $config=null, $time=null, $interval=null, $max_time=null)
Create a job object.
Definition: Worker.php:60
Rsi\Fred\Worker\$sleepTime
$sleepTime
Time to sleep when there are no more jobs scheduled (but still within minTime; seconds).
Definition: Worker.php:13
Rsi\Fred\Worker\ready
ready($job)
Mark a job as done.
Definition: Worker.php:109
Rsi\Fred\Worker\lock
lock($job)
Lock a job.
Definition: Worker.php:85
Rsi\Fred\Exception
Definition: Exception.php:5
Rsi\Fred
Definition: Alive.php:3