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

https://gitlab.com/ealexis.t/trends · PHP · 319 lines · 119 code · 42 blank · 158 comment · 3 complexity · 2945f655b403c580aa6148502846aa33 MD5 · raw file

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