Timer.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. <?php
  2. /**
  3. * This file is part of workerman.
  4. *
  5. * Licensed under The MIT License
  6. * For full copyright and license information, please see the MIT-LICENSE.txt
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @author walkor<walkor@workerman.net>
  10. * @copyright walkor<walkor@workerman.net>
  11. * @link http://www.workerman.net/
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Workerman;
  15. use Workerman\Events\EventInterface;
  16. use Workerman\Events\Select;
  17. use Workerman\Worker;
  18. use \Exception;
  19. /**
  20. * Timer.
  21. */
  22. class Timer
  23. {
  24. /**
  25. * Tasks that based on ALARM signal.
  26. * [
  27. * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
  28. * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
  29. * ..
  30. * ]
  31. *
  32. * @var array
  33. */
  34. protected static $_tasks = [];
  35. /**
  36. * event
  37. *
  38. * @var Select
  39. */
  40. protected static $_event = null;
  41. /**
  42. * timer id
  43. *
  44. * @var int
  45. */
  46. protected static $_timerId = 0;
  47. /**
  48. * timer status
  49. * [
  50. * timer_id1 => bool,
  51. * timer_id2 => bool,
  52. * ....................,
  53. * ]
  54. *
  55. * @var array
  56. */
  57. protected static $_status = [];
  58. /**
  59. * Init.
  60. *
  61. * @param EventInterface $event
  62. * @return void
  63. */
  64. public static function init($event = null)
  65. {
  66. if ($event) {
  67. self::$_event = $event;
  68. return;
  69. }
  70. if (\function_exists('pcntl_signal')) {
  71. \pcntl_signal(\SIGALRM, ['\Workerman\Timer', 'signalHandle'], false);
  72. }
  73. }
  74. /**
  75. * ALARM signal handler.
  76. *
  77. * @return void
  78. */
  79. public static function signalHandle()
  80. {
  81. if (!self::$_event) {
  82. \pcntl_alarm(1);
  83. self::tick();
  84. }
  85. }
  86. /**
  87. * Add a timer.
  88. *
  89. * @param float $time_interval
  90. * @param callable $func
  91. * @param mixed $args
  92. * @param bool $persistent
  93. * @return int|bool
  94. */
  95. public static function add(float $time_interval, $func, $args = [], $persistent = true)
  96. {
  97. if ($time_interval < 0) {
  98. Worker::safeEcho(new Exception("bad time_interval"));
  99. return false;
  100. }
  101. if ($args === null) {
  102. $args = [];
  103. }
  104. if (self::$_event) {
  105. return $persistent ? self::$_event->repeat($time_interval, $func, $args) : self::$_event->delay($time_interval, $func, $args);
  106. }
  107. // If not workerman runtime just return.
  108. if (!Worker::getAllWorkers()) {
  109. return;
  110. }
  111. if (!\is_callable($func)) {
  112. Worker::safeEcho(new Exception("not callable"));
  113. return false;
  114. }
  115. if (empty(self::$_tasks)) {
  116. \pcntl_alarm(1);
  117. }
  118. $run_time = \time() + $time_interval;
  119. if (!isset(self::$_tasks[$run_time])) {
  120. self::$_tasks[$run_time] = [];
  121. }
  122. self::$_timerId = self::$_timerId == \PHP_INT_MAX ? 1 : ++self::$_timerId;
  123. self::$_status[self::$_timerId] = true;
  124. self::$_tasks[$run_time][self::$_timerId] = [$func, (array)$args, $persistent, $time_interval];
  125. return self::$_timerId;
  126. }
  127. /**
  128. * @param float $delay
  129. * @param $func
  130. * @param array $args
  131. * @return bool|int
  132. */
  133. public static function delay(float $delay, $func, $args = [])
  134. {
  135. return static::add($delay, $func, $args, false);
  136. }
  137. /**
  138. * Tick.
  139. *
  140. * @return void
  141. */
  142. public static function tick()
  143. {
  144. if (empty(self::$_tasks)) {
  145. \pcntl_alarm(0);
  146. return;
  147. }
  148. $time_now = \time();
  149. foreach (self::$_tasks as $run_time => $task_data) {
  150. if ($time_now >= $run_time) {
  151. foreach ($task_data as $index => $one_task) {
  152. $task_func = $one_task[0];
  153. $task_args = $one_task[1];
  154. $persistent = $one_task[2];
  155. $time_interval = $one_task[3];
  156. try {
  157. $task_func(...$task_args);
  158. } catch (\Throwable $e) {
  159. Worker::safeEcho($e);
  160. }
  161. if($persistent && !empty(self::$_status[$index])) {
  162. $new_run_time = \time() + $time_interval;
  163. if(!isset(self::$_tasks[$new_run_time])) self::$_tasks[$new_run_time] = [];
  164. self::$_tasks[$new_run_time][$index] = [$task_func, (array)$task_args, $persistent, $time_interval];
  165. }
  166. }
  167. unset(self::$_tasks[$run_time]);
  168. }
  169. }
  170. }
  171. /**
  172. * Remove a timer.
  173. *
  174. * @param mixed $timer_id
  175. * @return bool
  176. */
  177. public static function del($timer_id)
  178. {
  179. if (self::$_event) {
  180. return self::$_event->deleteTimer($timer_id);
  181. }
  182. foreach(self::$_tasks as $run_time => $task_data)
  183. {
  184. if(array_key_exists($timer_id, $task_data)) unset(self::$_tasks[$run_time][$timer_id]);
  185. }
  186. if(array_key_exists($timer_id, self::$_status)) unset(self::$_status[$timer_id]);
  187. return true;
  188. }
  189. /**
  190. * Remove all timers.
  191. *
  192. * @return void
  193. */
  194. public static function delAll()
  195. {
  196. self::$_tasks = self::$_status = [];
  197. \pcntl_alarm(0);
  198. if (self::$_event) {
  199. self::$_event->deleteAllTimer();
  200. }
  201. }
  202. }