PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.8.0
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.8.0
4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / BackgroundProcessing / BackgroundProcessingServiceProvider.php
wp-staging / Framework / BackgroundProcessing Last commit date
Exceptions 5 years ago Action.php 2 years ago BackgroundProcessingServiceProvider.php 2 years ago Demo.php 4 years ago FeatureDetection.php 2 years ago Queue.php 2 years ago QueueActionAware.php 4 years ago QueueProcessor.php 2 years ago WithQueueAwareness.php 3 years ago
BackgroundProcessingServiceProvider.php
191 lines
1 <?php
2
3 /**
4 * Manages the registration and hooking of the Background Processing support feature.
5 *
6 * @package WPStaging\Framework\BackgroundProcessing
7 */
8
9 namespace WPStaging\Framework\BackgroundProcessing;
10
11 use WPStaging\Core\Cron\Cron;
12 use WPStaging\Framework\Adapter\Database;
13 use WPStaging\Framework\Adapter\Database\InterfaceDatabaseClient;
14 use WPStaging\Framework\DI\FeatureServiceProvider;
15
16 use function WPStaging\functions\debug_log;
17
18 /**
19 * Class BackgroundProcessingServiceProvider
20 *
21 * @property \tad_DI52_Container container
22 * @package WPStaging\Framework\BackgroundProcessing
23 */
24 class BackgroundProcessingServiceProvider extends FeatureServiceProvider
25 {
26 /**
27 * {@inheritdoc}
28 */
29 public static function getFeatureTrigger()
30 {
31 return 'WPSTG_FEATURE_ENABLE_BACKGROUND_PROCESSING';
32 }
33
34 /**
35 * Registers the required Cron actions and the classes used by the feature provider.
36 *
37 * @return bool Whether the feature registration was actually done or not.
38 */
39 public function register()
40 {
41 // This allows us to disable or enable the feature by setting WPSTG_FEATURE_ENABLE_BACKGROUND_PROCESSING to false/true in wp-config.php
42 if (!static::isEnabledInProduction()) {
43 return false;
44 }
45
46 $database = $this->container->make(Database::class)->getClient();
47
48 // See if there is better way than this to handle this code?
49 $this->container->when(Queue::class)
50 ->needs(InterfaceDatabaseClient::class)
51 ->give($database);
52
53 // For caching purposes, have one single instance of the Queue around.
54 $this->container->singleton(Queue::class, Queue::class);
55 // For concurrency purposes, have one single instance of the Queue processor around.
56 $this->container->singleton(QueueProcessor::class, QueueProcessor::class);
57
58 $this->registerFeatureDetection();
59 $this->scheduleQueueMaintenance();
60 $this->setupQueueProcessingEntrypoints();
61
62 return true;
63 }
64
65 /**
66 * Runs the Queue maintenance routines.
67 *
68 * @return void The method will not return any value.
69 */
70 public function runQueueMaintenance()
71 {
72 debug_log('Running Queue Maintenance.', 'info', false);
73
74 /** @var Queue $queue */
75 $queue = $this->container->make(Queue::class);
76
77 // Mark all dangling Actions as Failed.
78 $queue->markDanglingAs(Queue::STATUS_FAILED);
79 // Remove old Actions.
80 $queue->cleanup();
81 }
82
83 /**
84 * Schedules the Queue maintenance by means of the Cron. The Cron is not
85 * a really reliable method to execute timely tasks in WordPress, especially
86 * if not powered by a real cron, but it's fine for addressing the maintenance
87 * operations of the Queue that do not require to be timely and are fine happening
88 * when possible.
89 *
90 * @since TBD
91 *
92 */
93 private function scheduleQueueMaintenance()
94 {
95 // Once a day fire an action to run the Queue maintenance routines.
96 if (!wp_next_scheduled('wpstg_queue_maintain')) {
97 wp_schedule_event(time(), Cron::DAILY, 'wpstg_queue_maintain');
98 }
99
100 // When the action fires, run the maintenance routines.
101 add_action('wpstg_queue_maintain', [$this, 'runQueueMaintenance']);
102 }
103
104 /**
105 * Sets up the Queue processing entry points.
106 *
107 * The Queue, when loaded with Actions, has the potential to soak resources.
108 * The Queue Processor will have safeguards in place to avoid this, but we should
109 * be careful about the entrypoints of the queue processing to make sure it will
110 * process Actions only when doing that will not compromise the user experience.
111 * This is why we rely on side-processes that we can trigger while the main PHP process
112 * that is handling the user interaction with the site stays fast and snappy.
113 *
114 * @return void The method does not return any value.
115 */
116 private function setupQueueProcessingEntrypoints()
117 {
118 /**
119 * This is the core of how the Queue works: when the `wpstg_queue_process`, or the AJAX version of it, fires, we'll process some
120 * Actions.
121 * Setting up how we make these WordPress actions fire is what we take care of next.
122 */
123 $wpActions = [
124 QueueProcessor::QUEUE_PROCESS_ACTION,
125 'wp_ajax_nopriv_' . QueueProcessor::QUEUE_PROCESS_ACTION,
126 'wp_ajax_' . QueueProcessor::QUEUE_PROCESS_ACTION,
127 ];
128 $queueProcessorProcess = $this->container->callback(QueueProcessor::class, 'process');
129
130 foreach ($wpActions as $wpAction) {
131 if (!has_action($wpAction, $queueProcessorProcess)) {
132 add_action($wpAction, $queueProcessorProcess); // phpcs:ignore WPStaging.Security.FirstArgNotAString -- Queue action callbacks should not take input from request.
133 }
134 }
135
136 /*
137 * The first way we trigger the action that will make the Queue Processor process Actions is a Cron schedule.
138 * With full-knowledge of the fact that it will not be reliable, we still try to get some work done
139 * on Cron calls.
140 * Once every hour (kinda, it's Cron), fire the `wpstg_queue_process` action.
141 */
142 if (!wp_next_scheduled('wpstg_queue_process')) {
143 wp_schedule_event(time(), Cron::HOURLY, QueueProcessor::QUEUE_PROCESS_ACTION);
144 }
145
146 /*
147 * This is currently deactivated while we decide if supporting this is something we would like to do at all.
148 if (is_admin() && !wp_doing_ajax()) {
149 $ajaxAvailable = $this->container->make(FeatureDetection::class)->isAjaxAvailable(false);
150
151 if (!$ajaxAvailable) {
152 // add_action('shutdown', $queueProcessorProcess, -10000);
153 }
154 }
155 */
156 }
157
158 /**
159 * Registers the two actions that will be called by the AJAX support
160 * feature detection.
161 *
162 * @since TBD
163 */
164 private function registerFeatureDetection()
165 {
166 // Register the method that will handle the AJAX check.
167 $updateOption = $this->container->callback(FeatureDetection::class, 'updateAjaxTestOption');
168 // Hook on authenticated AJAX endpoint to handle the check.
169 add_action('wp_ajax_' . FeatureDetection::AJAX_TEST_ACTION, $updateOption); // phpcs:ignore WPStaging.Security.AuthorizationChecked -- Public
170 add_action('wp_ajax_nopriv_' . FeatureDetection::AJAX_TEST_ACTION, $updateOption); // phpcs:ignore WPStaging.Security.AuthorizationChecked -- Public
171
172 // Once a week re-run the check.
173 if (!wp_next_scheduled('wpstg_q_ajax_support_feature_detection')) {
174 wp_schedule_event(time(), Cron::WEEKLY, 'wpstg_q_ajax_support_feature_detection');
175 }
176
177 $runAjaxFeatureTest = $this->container->callback(FeatureDetection::class, 'runAjaxFeatureTest');
178 add_action('wpstg_q_ajax_support_feature_detection', $runAjaxFeatureTest);
179
180 // Run the test again if requested by link, e.g. from the notice.
181 if (
182 is_admin()
183 && filter_input(INPUT_GET, FeatureDetection::AJAX_REQUEST_QUERY_VAR, FILTER_SANITIZE_NUMBER_INT)
184 ) {
185 $runAjaxFeatureTest();
186 wp_redirect(remove_query_arg(FeatureDetection::AJAX_REQUEST_QUERY_VAR));
187 die();
188 }
189 }
190 }
191