| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 |
- <?php
- /**
- * Background worker for the scheduled backup and heartbeat.
- *
- * Same shape and same trust model as worker.php: the caller is this server
- * making an HTTP request to itself, so there is no admin session to check and
- * the key in data/worker-key.json authenticates instead. A wrong or missing key
- * is indistinguishable from the script not existing.
- *
- * Reached in three ways, all of which run the same code:
- *
- * - an admin page load past the interval (manage_kick(), app/manage.php),
- * - real cron, if the host has it: curl this URL every 15 minutes,
- * - by hand, when testing.
- *
- * What it never does is update the software. That is a deliberate act, from
- * Admin -> Maintenance.
- */
- require __DIR__ . '/app/bootstrap.php';
- if (!hash_equals(archive_worker_key(), (string)($_GET['key'] ?? ''))) {
- http_response_code(404);
- exit;
- }
- // The dispatcher hung up after a fraction of a second. Without this, PHP would
- // kill this process the moment it noticed the disconnect.
- ignore_user_abort(true);
- @set_time_limit(0);
- // Nothing is ever read from the response — the caller is not listening.
- http_response_code(204);
- if (function_exists('fastcgi_finish_request')) {
- @fastcgi_finish_request();
- }
- // One backup at a time. The client refuses concurrent runs itself, but with an
- // exception in the log; taking the lock here keeps that noise out and lets an
- // overlapping worker leave quietly.
- $lock = fopen(DATA_DIR . '/manage.lock', 'c');
- if ($lock === false || !flock($lock, LOCK_EX | LOCK_NB)) {
- exit;
- }
- $done = manage_run_due();
- flock($lock, LOCK_UN);
- fclose($lock);
- if ($done !== []) {
- manageClientLog('INFO', 'Scheduled run finished', ['jobs' => $done]);
- }
|