Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
CronTimeoutHandler
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 unlockJob
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Cron;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use PDO;
12
13/**
14 * Cron Job Timeout Recovery Handler.
15 *
16 * Handles resetting execution state and recording timeout logs for stalled cron jobs.
17 *
18 * @package App\Core\Cron
19 */
20final class CronTimeoutHandler
21{
22    /** @var string Database datetime format. */
23    private const string DATETIME_FORMAT = 'Y-m-d H:i:s';
24
25    /**
26     * Unlocks a timed-out cron job and writes failure log.
27     *
28     * @param PDO    $pdo            Database connection.
29     * @param string $tablePrefix    Table prefix.
30     * @param int    $jobId          Cron job ID.
31     * @param int    $elapsedSeconds Elapsed execution seconds.
32     * @param int    $timeoutSeconds Configured timeout threshold.
33     */
34    public static function unlockJob(
35        PDO $pdo,
36        string $tablePrefix,
37        int $jobId,
38        int $elapsedSeconds,
39        int $timeoutSeconds
40    ): void {
41        $cronTable = $tablePrefix . 'mod_cron_records';
42        $logTable = $tablePrefix . 'logs_cron_records';
43        $now = date(self::DATETIME_FORMAT);
44
45        $updateSql = sprintf(
46            'UPDATE `%s` SET `is_running` = 0, `last_status` = 0, `updated_at` = :now WHERE `id` = :id',
47            $cronTable
48        );
49        $updateStmt = $pdo->prepare($updateSql);
50        $updateStmt->execute([
51            ':now' => $now,
52            ':id'  => $jobId,
53        ]);
54
55        $logSql = sprintf(
56            'INSERT INTO `%s` (`job_id`, `status`, `duration_ms`, `memory_peak_bytes`, '
57            . '`error_message`, `created_at`) VALUES (:job_id, 0, :duration_ms, 0, :error_msg, :now)',
58            $logTable
59        );
60        $logStmt = $pdo->prepare($logSql);
61        $logStmt->execute([
62            ':job_id'      => $jobId,
63            ':duration_ms' => $elapsedSeconds * 1000,
64            ':error_msg'   => sprintf(
65                'Job execution timed out after %d seconds (limit: %d)',
66                $elapsedSeconds,
67                $timeoutSeconds
68            ),
69            ':now'         => $now,
70        ]);
71    }
72}