Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Queue;
4
 
5
use Illuminate\Contracts\Queue\ClearableQueue;
6
use Illuminate\Contracts\Queue\Queue as QueueContract;
7
use Illuminate\Contracts\Redis\Factory as Redis;
8
use Illuminate\Queue\Jobs\RedisJob;
9
use Illuminate\Support\Str;
10
 
11
class RedisQueue extends Queue implements QueueContract, ClearableQueue
12
{
13
    /**
14
     * The Redis factory implementation.
15
     *
16
     * @var \Illuminate\Contracts\Redis\Factory
17
     */
18
    protected $redis;
19
 
20
    /**
21
     * The connection name.
22
     *
23
     * @var string
24
     */
25
    protected $connection;
26
 
27
    /**
28
     * The name of the default queue.
29
     *
30
     * @var string
31
     */
32
    protected $default;
33
 
34
    /**
35
     * The expiration time of a job.
36
     *
37
     * @var int|null
38
     */
39
    protected $retryAfter = 60;
40
 
41
    /**
42
     * The maximum number of seconds to block for a job.
43
     *
44
     * @var int|null
45
     */
46
    protected $blockFor = null;
47
 
48
    /**
49
     * The batch size to use when migrating delayed / expired jobs onto the primary queue.
50
     *
51
     * Negative values are infinite.
52
     *
53
     * @var int
54
     */
55
    protected $migrationBatchSize = -1;
56
 
57
    /**
58
     * Create a new Redis queue instance.
59
     *
60
     * @param  \Illuminate\Contracts\Redis\Factory  $redis
61
     * @param  string  $default
62
     * @param  string|null  $connection
63
     * @param  int  $retryAfter
64
     * @param  int|null  $blockFor
65
     * @param  bool  $dispatchAfterCommit
66
     * @param  int  $migrationBatchSize
67
     * @return void
68
     */
69
    public function __construct(Redis $redis,
70
                                $default = 'default',
71
                                $connection = null,
72
                                $retryAfter = 60,
73
                                $blockFor = null,
74
                                $dispatchAfterCommit = false,
75
                                $migrationBatchSize = -1)
76
    {
77
        $this->redis = $redis;
78
        $this->default = $default;
79
        $this->blockFor = $blockFor;
80
        $this->connection = $connection;
81
        $this->retryAfter = $retryAfter;
82
        $this->dispatchAfterCommit = $dispatchAfterCommit;
83
        $this->migrationBatchSize = $migrationBatchSize;
84
    }
85
 
86
    /**
87
     * Get the size of the queue.
88
     *
89
     * @param  string|null  $queue
90
     * @return int
91
     */
92
    public function size($queue = null)
93
    {
94
        $queue = $this->getQueue($queue);
95
 
96
        return $this->getConnection()->eval(
97
            LuaScripts::size(), 3, $queue, $queue.':delayed', $queue.':reserved'
98
        );
99
    }
100
 
101
    /**
102
     * Push an array of jobs onto the queue.
103
     *
104
     * @param  array  $jobs
105
     * @param  mixed  $data
106
     * @param  string|null  $queue
107
     * @return void
108
     */
109
    public function bulk($jobs, $data = '', $queue = null)
110
    {
111
        $this->getConnection()->pipeline(function () use ($jobs, $data, $queue) {
112
            $this->getConnection()->transaction(function () use ($jobs, $data, $queue) {
113
                foreach ((array) $jobs as $job) {
114
                    if (isset($job->delay)) {
115
                        $this->later($job->delay, $job, $data, $queue);
116
                    } else {
117
                        $this->push($job, $data, $queue);
118
                    }
119
                }
120
            });
121
        });
122
    }
123
 
124
    /**
125
     * Push a new job onto the queue.
126
     *
127
     * @param  object|string  $job
128
     * @param  mixed  $data
129
     * @param  string|null  $queue
130
     * @return mixed
131
     */
132
    public function push($job, $data = '', $queue = null)
133
    {
134
        return $this->enqueueUsing(
135
            $job,
136
            $this->createPayload($job, $this->getQueue($queue), $data),
137
            $queue,
138
            null,
139
            function ($payload, $queue) {
140
                return $this->pushRaw($payload, $queue);
141
            }
142
        );
143
    }
144
 
145
    /**
146
     * Push a raw payload onto the queue.
147
     *
148
     * @param  string  $payload
149
     * @param  string|null  $queue
150
     * @param  array  $options
151
     * @return mixed
152
     */
153
    public function pushRaw($payload, $queue = null, array $options = [])
154
    {
155
        $this->getConnection()->eval(
156
            LuaScripts::push(), 2, $this->getQueue($queue),
157
            $this->getQueue($queue).':notify', $payload
158
        );
159
 
160
        return json_decode($payload, true)['id'] ?? null;
161
    }
162
 
163
    /**
164
     * Push a new job onto the queue after a delay.
165
     *
166
     * @param  \DateTimeInterface|\DateInterval|int  $delay
167
     * @param  object|string  $job
168
     * @param  mixed  $data
169
     * @param  string|null  $queue
170
     * @return mixed
171
     */
172
    public function later($delay, $job, $data = '', $queue = null)
173
    {
174
        return $this->enqueueUsing(
175
            $job,
176
            $this->createPayload($job, $this->getQueue($queue), $data),
177
            $queue,
178
            $delay,
179
            function ($payload, $queue, $delay) {
180
                return $this->laterRaw($delay, $payload, $queue);
181
            }
182
        );
183
    }
184
 
185
    /**
186
     * Push a raw job onto the queue after (n) seconds.
187
     *
188
     * @param  \DateTimeInterface|\DateInterval|int  $delay
189
     * @param  string  $payload
190
     * @param  string|null  $queue
191
     * @return mixed
192
     */
193
    protected function laterRaw($delay, $payload, $queue = null)
194
    {
195
        $this->getConnection()->zadd(
196
            $this->getQueue($queue).':delayed', $this->availableAt($delay), $payload
197
        );
198
 
199
        return json_decode($payload, true)['id'] ?? null;
200
    }
201
 
202
    /**
203
     * Create a payload string from the given job and data.
204
     *
205
     * @param  string  $job
206
     * @param  string  $queue
207
     * @param  mixed  $data
208
     * @return array
209
     */
210
    protected function createPayloadArray($job, $queue, $data = '')
211
    {
212
        return array_merge(parent::createPayloadArray($job, $queue, $data), [
213
            'id' => $this->getRandomId(),
214
            'attempts' => 0,
215
        ]);
216
    }
217
 
218
    /**
219
     * Pop the next job off of the queue.
220
     *
221
     * @param  string|null  $queue
222
     * @return \Illuminate\Contracts\Queue\Job|null
223
     */
224
    public function pop($queue = null)
225
    {
226
        $this->migrate($prefixed = $this->getQueue($queue));
227
 
228
        [$job, $reserved] = $this->retrieveNextJob($prefixed);
229
 
230
        if ($reserved) {
231
            return new RedisJob(
232
                $this->container, $this, $job,
233
                $reserved, $this->connectionName, $queue ?: $this->default
234
            );
235
        }
236
    }
237
 
238
    /**
239
     * Migrate any delayed or expired jobs onto the primary queue.
240
     *
241
     * @param  string  $queue
242
     * @return void
243
     */
244
    protected function migrate($queue)
245
    {
246
        $this->migrateExpiredJobs($queue.':delayed', $queue);
247
 
248
        if (! is_null($this->retryAfter)) {
249
            $this->migrateExpiredJobs($queue.':reserved', $queue);
250
        }
251
    }
252
 
253
    /**
254
     * Migrate the delayed jobs that are ready to the regular queue.
255
     *
256
     * @param  string  $from
257
     * @param  string  $to
258
     * @param  int  $limit
259
     * @return array
260
     */
261
    public function migrateExpiredJobs($from, $to)
262
    {
263
        return $this->getConnection()->eval(
264
            LuaScripts::migrateExpiredJobs(), 3, $from, $to, $to.':notify', $this->currentTime(), $this->migrationBatchSize
265
        );
266
    }
267
 
268
    /**
269
     * Retrieve the next job from the queue.
270
     *
271
     * @param  string  $queue
272
     * @param  bool  $block
273
     * @return array
274
     */
275
    protected function retrieveNextJob($queue, $block = true)
276
    {
277
        $nextJob = $this->getConnection()->eval(
278
            LuaScripts::pop(), 3, $queue, $queue.':reserved', $queue.':notify',
279
            $this->availableAt($this->retryAfter)
280
        );
281
 
282
        if (empty($nextJob)) {
283
            return [null, null];
284
        }
285
 
286
        [$job, $reserved] = $nextJob;
287
 
288
        if (! $job && ! is_null($this->blockFor) && $block &&
289
            $this->getConnection()->blpop([$queue.':notify'], $this->blockFor)) {
290
            return $this->retrieveNextJob($queue, false);
291
        }
292
 
293
        return [$job, $reserved];
294
    }
295
 
296
    /**
297
     * Delete a reserved job from the queue.
298
     *
299
     * @param  string  $queue
300
     * @param  \Illuminate\Queue\Jobs\RedisJob  $job
301
     * @return void
302
     */
303
    public function deleteReserved($queue, $job)
304
    {
305
        $this->getConnection()->zrem($this->getQueue($queue).':reserved', $job->getReservedJob());
306
    }
307
 
308
    /**
309
     * Delete a reserved job from the reserved queue and release it.
310
     *
311
     * @param  string  $queue
312
     * @param  \Illuminate\Queue\Jobs\RedisJob  $job
313
     * @param  int  $delay
314
     * @return void
315
     */
316
    public function deleteAndRelease($queue, $job, $delay)
317
    {
318
        $queue = $this->getQueue($queue);
319
 
320
        $this->getConnection()->eval(
321
            LuaScripts::release(), 2, $queue.':delayed', $queue.':reserved',
322
            $job->getReservedJob(), $this->availableAt($delay)
323
        );
324
    }
325
 
326
    /**
327
     * Delete all of the jobs from the queue.
328
     *
329
     * @param  string  $queue
330
     * @return int
331
     */
332
    public function clear($queue)
333
    {
334
        $queue = $this->getQueue($queue);
335
 
336
        return $this->getConnection()->eval(
337
            LuaScripts::clear(), 4, $queue, $queue.':delayed',
338
            $queue.':reserved', $queue.':notify'
339
        );
340
    }
341
 
342
    /**
343
     * Get a random ID string.
344
     *
345
     * @return string
346
     */
347
    protected function getRandomId()
348
    {
349
        return Str::random(32);
350
    }
351
 
352
    /**
353
     * Get the queue or return the default.
354
     *
355
     * @param  string|null  $queue
356
     * @return string
357
     */
358
    public function getQueue($queue)
359
    {
360
        return 'queues:'.($queue ?: $this->default);
361
    }
362
 
363
    /**
364
     * Get the connection for the queue.
365
     *
366
     * @return \Illuminate\Redis\Connections\Connection
367
     */
368
    public function getConnection()
369
    {
370
        return $this->redis->connection($this->connection);
371
    }
372
 
373
    /**
374
     * Get the underlying Redis instance.
375
     *
376
     * @return \Illuminate\Contracts\Redis\Factory
377
     */
378
    public function getRedis()
379
    {
380
        return $this->redis;
381
    }
382
}