Issues (10)

src/WP_Queue/Cron.php (6 issues)

Labels
Severity
1
<?php
2
3
namespace WP_Queue;
4
5
class Cron {
6
7
	/**
8
	 * @var string
9
	 */
10
	protected $id;
11
12
	/**
13
	 * @var Worker
14
	 */
15
	protected $worker;
16
17
	/**
18
	 * @var int
19
	 */
20
	protected $interval;
21
22
	/**
23
	 * Timestamp of when processing the queue started.
24
	 *
25
	 * @var int
26
	 */
27
	protected $start_time;
28
29
	/**
30
	 * Cron constructor.
31
	 *
32
	 * @param string $id
33
	 * @param Worker $worker
34
	 * @param int    $interval
35
	 */
36 1
	public function __construct( $id, $worker, $interval ) {
37 1
		$this->id       = strtolower( str_replace( '\\', '_', $id ) );
38 1
		$this->worker   = $worker;
39 1
		$this->interval = $interval;
40 1
	}
41
42
	/**
43
	 * Is the cron queue worker enabled?
44
	 *
45
	 * @return bool
46
	 */
47 1
	protected function is_enabled() {
48 1
		if ( defined( 'DISABLE_WP_QUEUE_CRON' ) && DISABLE_WP_QUEUE_CRON ) {
0 ignored issues
show
The constant WP_Queue\DISABLE_WP_QUEUE_CRON was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
49
			return false;
50
		}
51
52 1
		return true;
53
	}
54
55
	/**
56
	 * Init cron class.
57
	 *
58
	 * @return bool
59
	 */
60 1
	public function init() {
61 1
		if ( ! $this->is_enabled() ) {
62
			return false;
63
		}
64
65 1
		add_filter( 'cron_schedules', array( $this, 'schedule_cron' ) );
66 1
		add_action( $this->id, array( $this, 'cron_worker' ) );
67
68 1
		if ( ! wp_next_scheduled( $this->id ) ) {
69
			// Schedule health check
70
			wp_schedule_event( time(), $this->id, $this->id );
0 ignored issues
show
The function wp_schedule_event 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

70
			/** @scrutinizer ignore-call */ 
71
   wp_schedule_event( time(), $this->id, $this->id );
Loading history...
71
		}
72
73 1
		return true;
74
	}
75
76
	/**
77
	 * Add interval to cron schedules.
78
	 *
79
	 * @param array $schedules
80
	 *
81
	 * @return array
82
	 */
83
	public function schedule_cron( $schedules ) {
84
		$schedules[ $this->id ] = array(
85
			'interval' => MINUTE_IN_SECONDS * $this->interval,
0 ignored issues
show
The constant WP_Queue\MINUTE_IN_SECONDS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
86
			'display'  => sprintf( __( 'Every %d Minutes' ), $this->interval ),
87
		);
88
89
		return $schedules;
90
	}
91
92
	/**
93
	 * Process any jobs in the queue.
94
	 */
95
	public function cron_worker() {
96
		if ( $this->is_worker_locked() ) {
97
			return;
98
		}
99
100
		$this->start_time = time();
101
102
		$this->lock_worker();
103
104
		while ( ! $this->time_exceeded() && ! $this->memory_exceeded() ) {
105
			if ( ! $this->worker->process() ) {
106
				break;
107
			}
108
		}
109
110
		$this->unlock_worker();
111
	}
112
113
	/**
114
	 * Is the cron worker locked?
115
	 *
116
	 * @return bool
117
	 */
118
	protected function is_worker_locked() {
119
		return (bool) get_site_transient( $this->id );
0 ignored issues
show
The function get_site_transient 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
		return (bool) /** @scrutinizer ignore-call */ get_site_transient( $this->id );
Loading history...
120
	}
121
122
	/**
123
	 * Lock the cron worker.
124
	 */
125
	protected function lock_worker() {
126
		set_site_transient( $this->id, time(), 300 );
0 ignored issues
show
The function set_site_transient 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
		/** @scrutinizer ignore-call */ 
127
  set_site_transient( $this->id, time(), 300 );
Loading history...
127
	}
128
129
	/**
130
	 * Unlock the cron worker.
131
	 */
132
	protected function unlock_worker() {
133
		delete_site_transient( $this->id );
0 ignored issues
show
The function delete_site_transient 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

133
		/** @scrutinizer ignore-call */ 
134
  delete_site_transient( $this->id );
Loading history...
134
	}
135
136
	/**
137
	 * Memory exceeded
138
	 *
139
	 * Ensures the worker process never exceeds 80%
140
	 * of the maximum allowed PHP memory.
141
	 *
142
	 * @return bool
143
	 */
144
	protected function memory_exceeded() {
145
		$memory_limit   = $this->get_memory_limit() * 0.8; // 80% of max memory
146
		$current_memory = memory_get_usage( true );
147
		$return         = false;
148
149
		if ( $current_memory >= $memory_limit ) {
150
			$return = true;
151
		}
152
153
		return apply_filters( 'wp_queue_cron_memory_exceeded', $return );
154
	}
155
156
	/**
157
	 * Get memory limit.
158
	 *
159
	 * @return int
160
	 */
161
	protected function get_memory_limit() {
162
		if ( function_exists( 'ini_get' ) ) {
163
			$memory_limit = ini_get( 'memory_limit' );
164
		} else {
165
			$memory_limit = '256M';
166
		}
167
168
		if ( ! $memory_limit || - 1 == $memory_limit ) {
169
			// Unlimited, set to 1GB
170
			$memory_limit = '1000M';
171
		}
172
173
		return intval( $memory_limit ) * 1024 * 1024;
174
	}
175
176
	/**
177
	 * Time exceeded
178
	 *
179
	 * Ensures the worker never exceeds a sensible time limit (20s by default).
180
	 * A timeout limit of 30s is common on shared hosting.
181
	 *
182
	 * @return bool
183
	 */
184
	protected function time_exceeded() {
185
		$finish = $this->start_time + apply_filters( 'wp_queue_cron_time_limit', 20 ); // 20 seconds
186
		$return = false;
187
188
		if ( time() >= $finish ) {
189
			$return = true;
190
		}
191
192
		return apply_filters( 'wp_queue_cron_time_exceeded', $return );
193
	}
194
}