CronJob::getGlobalTimerLock()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 11
rs 10
1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
3
namespace Hhxsv5\LaravelS\Swoole\Timer;
4
5
use Swoole\Timer;
6
7
abstract class CronJob implements CronJobInterface
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class CronJob
Loading history...
8
{
9
    /**
10
     * The seconds of global timer locking
11
     * @var int
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
12
     */
13
    const GLOBAL_TIMER_LOCK_SECONDS = 60;
14
15
    /**
16
     * Swoole timer id
17
     * @var int
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
18
     */
19
    protected $timerId;
20
21
    /**
22
     * The interval of Job in millisecond
23
     * @var int
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
24
     */
25
    protected $interval;
26
27
    /**
28
     * Whether run immediately after start
29
     * @var bool
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
30
     */
31
    protected $isImmediate;
32
33
    /**
34
     * The lock key of global timer
35
     * @var string
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
36
     */
37
    protected static $globalTimerLockKey;
38
39
    /**
40
     * Whether enable CronJob
41
     * @var bool
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
42
     */
43
    protected static $enable = true;
44
45
    /**
46
     * CronJob constructor.
47
     * Optional:
48
     *     argument 0 is interval, int ms, default null, overridden by method interval()
49
     *     argument 1 is isImmediate, bool, default false, overridden by method isImmediate()
50
     */
51
    public function __construct()
52
    {
53
        $args = func_get_args();
54
        $config = isset($args[0]) ? $args[0] : [];
55
        if (is_array($config)) {
56
            if (isset($config[0])) {
57
                $this->interval = $config[0];
58
            }
59
            if (isset($config[1])) {
60
                $this->isImmediate = $config[1];
61
            }
62
        }
63
    }
64
65
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
66
     * @return int
67
     */
68
    public function interval()
69
    {
70
        return $this->interval;
71
    }
72
73
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
74
     * @return bool
75
     */
76
    public function isImmediate()
77
    {
78
        return $this->isImmediate;
79
    }
80
81
    public function setTimerId($timerId)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function setTimerId()
Loading history...
82
    {
83
        $this->timerId = $timerId;
84
    }
85
86
    public function stop()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function stop()
Loading history...
87
    {
88
        if ($this->timerId && Timer::exists($this->timerId)) {
89
            Timer::clear($this->timerId);
90
        }
91
    }
92
93
    public static function getGlobalTimerCacheKey()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getGlobalTimerCacheKey()
Loading history...
94
    {
95
        return 'laravels:timer:' . strtolower(self::$globalTimerLockKey);
96
    }
97
98
    public static function getGlobalTimerLock()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getGlobalTimerLock()
Loading history...
99
    {
100
        /**@var \Illuminate\Redis\RedisManager $redis */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
101
        $redis = app('redis');
0 ignored issues
show
Bug introduced by
The function app was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
        $redis = /** @scrutinizer ignore-call */ app('redis');
Loading history...
102
103
        $key = self::getGlobalTimerCacheKey();
104
        $value = self::getCurrentInstanceId();
105
        $expire = self::GLOBAL_TIMER_LOCK_SECONDS;
106
        $result = $redis->set($key, $value, 'ex', $expire, 'nx');
107
        // Compatible with Predis and PhpRedis
108
        return $result === true || ((string)$result === 'OK');
109
    }
110
111
    protected static function getCurrentInstanceId()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getCurrentInstanceId()
Loading history...
112
    {
113
        return sprintf('%s:%d', current(swoole_get_local_ip()) ?: gethostname(), config('laravels.listen_port'));
0 ignored issues
show
Bug introduced by
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

113
        return sprintf('%s:%d', current(swoole_get_local_ip()) ?: gethostname(), /** @scrutinizer ignore-call */ config('laravels.listen_port'));
Loading history...
114
    }
115
116
    public static function isGlobalTimerAlive()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function isGlobalTimerAlive()
Loading history...
117
    {
118
        /**@var \Redis|\RedisCluster|\Predis\Client $redis */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
119
        $redis = app('redis')->client(); // Fix: Redis exists() always returns false on cluster mode for some older versions of Laravel/Lumen, see https://github.com/illuminate/redis/commit/62ff6a06a9c91902d3baa7feda20bab5e807606f
0 ignored issues
show
Bug introduced by
The function app was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

119
        $redis = /** @scrutinizer ignore-call */ app('redis')->client(); // Fix: Redis exists() always returns false on cluster mode for some older versions of Laravel/Lumen, see https://github.com/illuminate/redis/commit/62ff6a06a9c91902d3baa7feda20bab5e807606f
Loading history...
120
        return (bool)$redis->exists(self::getGlobalTimerCacheKey());
121
    }
122
123
    public static function isCurrentTimerAlive()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function isCurrentTimerAlive()
Loading history...
124
    {
125
        /**@var \Illuminate\Redis\RedisManager $redis */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
126
        $redis = app('redis');
0 ignored issues
show
Bug introduced by
The function app was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

126
        $redis = /** @scrutinizer ignore-call */ app('redis');
Loading history...
127
        $key = self::getGlobalTimerCacheKey();
128
        $instanceId = $redis->get($key);
129
        return $instanceId === self::getCurrentInstanceId();
130
    }
131
132
    public static function renewGlobalTimerLock($expire)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function renewGlobalTimerLock()
Loading history...
133
    {
134
        /**@var \Illuminate\Redis\RedisManager $redis */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
135
        $redis = app('redis');
0 ignored issues
show
Bug introduced by
The function app was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

135
        $redis = /** @scrutinizer ignore-call */ app('redis');
Loading history...
136
        return (bool)$redis->expire(self::getGlobalTimerCacheKey(), $expire);
137
    }
138
139
    public static function setGlobalTimerLockKey($lockKey)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function setGlobalTimerLockKey()
Loading history...
140
    {
141
        self::$globalTimerLockKey = $lockKey;
142
    }
143
144
    public static function checkSetEnable()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function checkSetEnable()
Loading history...
145
    {
146
        if (self::isGlobalTimerAlive()) {
147
            // Reset current timer to avoid repeated execution
148
            self::setEnable(self::isCurrentTimerAlive());
149
        } else {
150
            // Compete for timer lock
151
            self::setEnable(self::getGlobalTimerLock());
152
        }
153
    }
154
155
    public static function setEnable($enable)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function setEnable()
Loading history...
156
    {
157
        self::$enable = (bool)$enable;
158
    }
159
160
    public static function isEnable()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function isEnable()
Loading history...
161
    {
162
        return self::$enable;
163
    }
164
}