/vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php

https://gitlab.com/techniconline/kmc · PHP · 317 lines · 116 code · 43 blank · 158 comment · 3 complexity · b843667f80bb4fdaa9058076abdbcfa5 MD5 · raw file

  1. <?php namespace Illuminate\Queue;
  2. use Illuminate\Redis\Database;
  3. use Illuminate\Queue\Jobs\RedisJob;
  4. use Illuminate\Contracts\Queue\Queue as QueueContract;
  5. class RedisQueue extends Queue implements QueueContract
  6. {
  7. /**
  8. * The Redis database instance.
  9. *
  10. * @var \Illuminate\Redis\Database
  11. */
  12. protected $redis;
  13. /**
  14. * The connection name.
  15. *
  16. * @var string
  17. */
  18. protected $connection;
  19. /**
  20. * The name of the default queue.
  21. *
  22. * @var string
  23. */
  24. protected $default;
  25. /**
  26. * The expiration time of a job.
  27. *
  28. * @var int|null
  29. */
  30. protected $expire = 60;
  31. /**
  32. * Create a new Redis queue instance.
  33. *
  34. * @param \Illuminate\Redis\Database $redis
  35. * @param string $default
  36. * @param string $connection
  37. * @return void
  38. */
  39. public function __construct(Database $redis, $default = 'default', $connection = null)
  40. {
  41. $this->redis = $redis;
  42. $this->default = $default;
  43. $this->connection = $connection;
  44. }
  45. /**
  46. * Push a new job onto the queue.
  47. *
  48. * @param string $job
  49. * @param mixed $data
  50. * @param string $queue
  51. * @return void
  52. */
  53. public function push($job, $data = '', $queue = null)
  54. {
  55. return $this->pushRaw($this->createPayload($job, $data), $queue);
  56. }
  57. /**
  58. * Push a raw payload onto the queue.
  59. *
  60. * @param string $payload
  61. * @param string $queue
  62. * @param array $options
  63. * @return mixed
  64. */
  65. public function pushRaw($payload, $queue = null, array $options = array())
  66. {
  67. $this->getConnection()->rpush($this->getQueue($queue), $payload);
  68. return array_get(json_decode($payload, true), 'id');
  69. }
  70. /**
  71. * Push a new job onto the queue after a delay.
  72. *
  73. * @param \DateTime|int $delay
  74. * @param string $job
  75. * @param mixed $data
  76. * @param string $queue
  77. * @return void
  78. */
  79. public function later($delay, $job, $data = '', $queue = null)
  80. {
  81. $payload = $this->createPayload($job, $data);
  82. $delay = $this->getSeconds($delay);
  83. $this->getConnection()->zadd($this->getQueue($queue) . ':delayed', $this->getTime() + $delay, $payload);
  84. return array_get(json_decode($payload, true), 'id');
  85. }
  86. /**
  87. * Release a reserved job back onto the queue.
  88. *
  89. * @param string $queue
  90. * @param string $payload
  91. * @param int $delay
  92. * @param int $attempts
  93. * @return void
  94. */
  95. public function release($queue, $payload, $delay, $attempts)
  96. {
  97. $payload = $this->setMeta($payload, 'attempts', $attempts);
  98. $this->getConnection()->zadd($this->getQueue($queue) . ':delayed', $this->getTime() + $delay, $payload);
  99. }
  100. /**
  101. * Pop the next job off of the queue.
  102. *
  103. * @param string $queue
  104. * @return \Illuminate\Contracts\Queue\Job|null
  105. */
  106. public function pop($queue = null)
  107. {
  108. $original = $queue ?: $this->default;
  109. $queue = $this->getQueue($queue);
  110. if (!is_null($this->expire)) {
  111. $this->migrateAllExpiredJobs($queue);
  112. }
  113. $job = $this->getConnection()->lpop($queue);
  114. if (!is_null($job)) {
  115. $this->getConnection()->zadd($queue . ':reserved', $this->getTime() + $this->expire, $job);
  116. return new RedisJob($this->container, $this, $job, $original);
  117. }
  118. }
  119. /**
  120. * Delete a reserved job from the queue.
  121. *
  122. * @param string $queue
  123. * @param string $job
  124. * @return void
  125. */
  126. public function deleteReserved($queue, $job)
  127. {
  128. $this->getConnection()->zrem($this->getQueue($queue) . ':reserved', $job);
  129. }
  130. /**
  131. * Migrate all of the waiting jobs in the queue.
  132. *
  133. * @param string $queue
  134. * @return void
  135. */
  136. protected function migrateAllExpiredJobs($queue)
  137. {
  138. $this->migrateExpiredJobs($queue . ':delayed', $queue);
  139. $this->migrateExpiredJobs($queue . ':reserved', $queue);
  140. }
  141. /**
  142. * Migrate the delayed jobs that are ready to the regular queue.
  143. *
  144. * @param string $from
  145. * @param string $to
  146. * @return void
  147. */
  148. public function migrateExpiredJobs($from, $to)
  149. {
  150. $options = ['cas' => true, 'watch' => $from, 'retry' => 10];
  151. $this->getConnection()->transaction($options, function ($transaction) use ($from, $to) {
  152. // First we need to get all of jobs that have expired based on the current time
  153. // so that we can push them onto the main queue. After we get them we simply
  154. // remove them from this "delay" queues. All of this within a transaction.
  155. $jobs = $this->getExpiredJobs(
  156. $transaction, $from, $time = $this->getTime()
  157. );
  158. // If we actually found any jobs, we will remove them from the old queue and we
  159. // will insert them onto the new (ready) "queue". This means they will stand
  160. // ready to be processed by the queue worker whenever their turn comes up.
  161. if (count($jobs) > 0) {
  162. $this->removeExpiredJobs($transaction, $from, $time);
  163. $this->pushExpiredJobsOntoNewQueue($transaction, $to, $jobs);
  164. }
  165. });
  166. }
  167. /**
  168. * Get the expired jobs from a given queue.
  169. *
  170. * @param \Predis\Transaction\MultiExec $transaction
  171. * @param string $from
  172. * @param int $time
  173. * @return array
  174. */
  175. protected function getExpiredJobs($transaction, $from, $time)
  176. {
  177. return $transaction->zrangebyscore($from, '-inf', $time);
  178. }
  179. /**
  180. * Remove the expired jobs from a given queue.
  181. *
  182. * @param \Predis\Transaction\MultiExec $transaction
  183. * @param string $from
  184. * @param int $time
  185. * @return void
  186. */
  187. protected function removeExpiredJobs($transaction, $from, $time)
  188. {
  189. $transaction->multi();
  190. $transaction->zremrangebyscore($from, '-inf', $time);
  191. }
  192. /**
  193. * Push all of the given jobs onto another queue.
  194. *
  195. * @param \Predis\Transaction\MultiExec $transaction
  196. * @param string $to
  197. * @param array $jobs
  198. * @return void
  199. */
  200. protected function pushExpiredJobsOntoNewQueue($transaction, $to, $jobs)
  201. {
  202. call_user_func_array([$transaction, 'rpush'], array_merge([$to], $jobs));
  203. }
  204. /**
  205. * Create a payload string from the given job and data.
  206. *
  207. * @param string $job
  208. * @param mixed $data
  209. * @param string $queue
  210. * @return string
  211. */
  212. protected function createPayload($job, $data = '', $queue = null)
  213. {
  214. $payload = parent::createPayload($job, $data);
  215. $payload = $this->setMeta($payload, 'id', $this->getRandomId());
  216. return $this->setMeta($payload, 'attempts', 1);
  217. }
  218. /**
  219. * Get a random ID string.
  220. *
  221. * @return string
  222. */
  223. protected function getRandomId()
  224. {
  225. return str_random(32);
  226. }
  227. /**
  228. * Get the queue or return the default.
  229. *
  230. * @param string|null $queue
  231. * @return string
  232. */
  233. protected function getQueue($queue)
  234. {
  235. return 'queues:' . ($queue ?: $this->default);
  236. }
  237. /**
  238. * Get the connection for the queue.
  239. *
  240. * @return \Predis\ClientInterface
  241. */
  242. protected function getConnection()
  243. {
  244. return $this->redis->connection($this->connection);
  245. }
  246. /**
  247. * Get the underlying Redis instance.
  248. *
  249. * @return \Illuminate\Redis\Database
  250. */
  251. public function getRedis()
  252. {
  253. return $this->redis;
  254. }
  255. /**
  256. * Get the expiration time in seconds.
  257. *
  258. * @return int|null
  259. */
  260. public function getExpire()
  261. {
  262. return $this->expire;
  263. }
  264. /**
  265. * Set the expiration time in seconds.
  266. *
  267. * @param int|null $seconds
  268. * @return void
  269. */
  270. public function setExpire($seconds)
  271. {
  272. $this->expire = $seconds;
  273. }
  274. }