mirror of
https://github.com/itflow-org/itflow
synced 2026-08-05 07:07:14 +00:00
Cron Fix
This commit is contained in:
191
admin/cron.php
Normal file
191
admin/cron.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
require_once "includes/inc_all_admin.php";
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/cron_jobs.php';
|
||||
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT config_enable_cron, config_cron_last_dispatch_at FROM settings WHERE company_id = 1"));
|
||||
|
||||
$config_enable_cron = intval($row['config_enable_cron']);
|
||||
$cron_last_dispatch_at = $row['config_cron_last_dispatch_at'];
|
||||
|
||||
// The dispatcher writes its heartbeat before it runs anything, so anything older than a few
|
||||
// minutes means the crontab entry itself is missing or failing - a different problem from a
|
||||
// job that is disabled or erroring, and the one people spend the longest not finding.
|
||||
$cron_is_running = $cron_last_dispatch_at !== null && (time() - strtotime($cron_last_dispatch_at)) < 300;
|
||||
|
||||
$cron_command = "* * * * * php " . dirname(__DIR__) . "/cron/cron.php >/dev/null";
|
||||
|
||||
// Registry order is dispatch order, so the table reads the way the cycle runs
|
||||
$cron_jobs = [];
|
||||
foreach (cronJobRegistry() as $job) {
|
||||
$cron_jobs[$job['name']] = $job;
|
||||
$cron_jobs[$job['name']]['row'] = null;
|
||||
}
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM cron_jobs");
|
||||
while ($job_row = mysqli_fetch_assoc($sql)) {
|
||||
if (isset($cron_jobs[$job_row['cron_job_name']])) {
|
||||
$cron_jobs[$job_row['cron_job_name']]['row'] = $job_row;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="card card-dark">
|
||||
<div class="card-header py-3">
|
||||
<h3 class="card-title"><i class="fas fa-fw fa-clock mr-2"></i>Cron</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<?php if (!$cron_is_running) { ?>
|
||||
<div class="alert alert-danger">
|
||||
<h5><i class="fas fa-fw fa-exclamation-triangle mr-2"></i>Cron is not running</h5>
|
||||
ITFlow last heard from cron <strong><?= escapeHtml(strtolower(cronJobTimeAgo($cron_last_dispatch_at))) ?></strong>.
|
||||
Nothing below will run - no mail is being sent, no email is being turned into tickets, and invoices are not being generated.
|
||||
Add this line to the crontab of the user that owns the ITFlow files:
|
||||
<pre class="bg-dark text-white p-2 mt-2 mb-0"><?= escapeHtml($cron_command) ?></pre>
|
||||
</div>
|
||||
<?php } else { ?>
|
||||
<div class="alert alert-success">
|
||||
<i class="fas fa-fw fa-check mr-2"></i>Cron last checked in <strong><?= escapeHtml(strtolower(cronJobTimeAgo($cron_last_dispatch_at))) ?></strong>.
|
||||
<span class="text-muted ml-2"><?= escapeHtml($cron_command) ?></span>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($config_enable_cron == 0) { ?>
|
||||
<div class="alert alert-warning">
|
||||
<i class="fas fa-fw fa-exclamation-circle mr-2"></i>Cron is switched off in
|
||||
<a href="settings_notification.php">Settings > Notifications</a>. The dispatcher is running, but most jobs
|
||||
stop themselves immediately while this is off.
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="table-responsive-sm">
|
||||
<table class="table table-borderless table-hover">
|
||||
<thead class="text-secondary">
|
||||
<tr>
|
||||
<th>Job</th>
|
||||
<th>Schedule</th>
|
||||
<th>Last Run</th>
|
||||
<th>Duration</th>
|
||||
<th>Status</th>
|
||||
<th>Next Run</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($cron_jobs as $job) {
|
||||
|
||||
$job_row = $job['row'];
|
||||
|
||||
// A job the dispatcher has not met yet has no row. It gets one on the next
|
||||
// pass, seeded from the schedule in the registry, so show that meanwhile.
|
||||
$cron_job_id = $job_row ? intval($job_row['cron_job_id']) : 0;
|
||||
$enabled = $job_row ? intval($job_row['cron_job_enabled']) : 1;
|
||||
$schedule = $job_row ? $job_row['cron_job_schedule'] : $job['schedule'];
|
||||
$interval_minutes = $job_row ? intval($job_row['cron_job_interval_minutes']) : intval($job['interval_minutes'] ?? 1);
|
||||
$daily_at = $job_row ? $job_row['cron_job_daily_at'] : ($job['daily_at'] ?? null);
|
||||
$run_now = $job_row ? intval($job_row['cron_job_run_now']) : 0;
|
||||
$last_run_at = $job_row ? $job_row['cron_job_last_run_at'] : null;
|
||||
$last_duration = $job_row ? $job_row['cron_job_last_duration'] : null;
|
||||
$last_status = $job_row ? $job_row['cron_job_last_status'] : null;
|
||||
$last_error = $job_row ? $job_row['cron_job_last_error'] : null;
|
||||
$last_error_at = $job_row ? $job_row['cron_job_last_error_at'] : null;
|
||||
|
||||
$next_run = $job_row ? cronJobNextRun($job_row) : null;
|
||||
|
||||
if ($run_now) {
|
||||
$status_badge = '<span class="badge badge-warning">Queued</span>';
|
||||
} elseif ($last_status === 'Running') {
|
||||
$status_badge = '<span class="badge badge-info">Running</span>';
|
||||
} elseif ($last_status === 'Completed') {
|
||||
$status_badge = '<span class="badge badge-success">Completed</span>';
|
||||
} elseif ($last_status === 'Failed') {
|
||||
$status_badge = '<span class="badge badge-danger">Failed</span>';
|
||||
} elseif ($last_status !== null) {
|
||||
$status_badge = '<span class="badge badge-secondary">Stopped</span>';
|
||||
} else {
|
||||
$status_badge = '<span class="badge badge-light">Never run</span>';
|
||||
}
|
||||
|
||||
?>
|
||||
<tr class="<?= $enabled ? '' : 'text-muted' ?>">
|
||||
<td>
|
||||
<strong><?= escapeHtml($job['label']) ?></strong>
|
||||
<?php if (!$enabled) { ?><span class="badge badge-secondary ml-1">Disabled</span><?php } ?>
|
||||
<br><small class="text-secondary"><?= escapeHtml($job['description']) ?></small>
|
||||
<br><small class="text-muted"><code>cron/<?= escapeHtml($job['script']) ?></code></small>
|
||||
</td>
|
||||
<td><?= escapeHtml(cronJobScheduleDescription($schedule, $interval_minutes, $daily_at)) ?></td>
|
||||
<td>
|
||||
<?= escapeHtml(cronJobTimeAgo($last_run_at)) ?>
|
||||
<?php if ($last_run_at) { ?><br><small class="text-muted"><?= escapeHtml(date('M j, g:i A', strtotime($last_run_at))) ?></small><?php } ?>
|
||||
</td>
|
||||
<td><?= $last_duration === null ? '-' : escapeHtml($last_duration) . 's' ?></td>
|
||||
<td>
|
||||
<?= $status_badge ?>
|
||||
<?php if ($last_status !== null && $last_status !== 'Running' && strlen($last_status) > 9) { ?>
|
||||
<br><small class="text-muted"><?= escapeHtml($last_status) ?></small>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td><?= $next_run === null ? '-' : escapeHtml(cronJobTimeAgo($next_run)) ?></td>
|
||||
<td class="text-center">
|
||||
<div class="dropdown dropleft text-center">
|
||||
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item <?= $cron_job_id === 0 ? 'disabled' : '' ?>" href="post.php?run_cron_job=<?= $cron_job_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<i class="fas fa-fw fa-play mr-2"></i>Run Now
|
||||
</a>
|
||||
<button class="dropdown-item ajax-modal <?= $cron_job_id === 0 ? 'disabled' : '' ?>" type="button" data-toggle="ajax-modal"
|
||||
data-modal-url="modals/cron/cron_edit.php?id=<?= $cron_job_id ?>">
|
||||
<i class="fas fa-fw fa-edit mr-2"></i>Edit Schedule
|
||||
</button>
|
||||
<?php if ($enabled) { ?>
|
||||
<a class="dropdown-item text-danger" href="post.php?disable_cron_job=<?= $cron_job_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<i class="fas fa-fw fa-pause mr-2"></i>Disable
|
||||
</a>
|
||||
<?php } else { ?>
|
||||
<a class="dropdown-item text-success" href="post.php?enable_cron_job=<?= $cron_job_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<i class="fas fa-fw fa-play-circle mr-2"></i>Enable
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if (!empty($last_error)) { ?>
|
||||
<tr>
|
||||
<td colspan="7" class="pt-0">
|
||||
<div class="alert alert-danger mb-0 py-2">
|
||||
<div class="float-right">
|
||||
<a class="text-danger" href="post.php?clear_cron_error=<?= $cron_job_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>" title="Dismiss">
|
||||
<i class="fas fa-fw fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
<strong><i class="fas fa-fw fa-exclamation-triangle mr-2"></i>Last error</strong>
|
||||
<small class="text-muted ml-2"><?= escapeHtml(cronJobTimeAgo($last_error_at)) ?></small>
|
||||
<div class="mt-1"><small><?= escapeHtml($last_error) ?></small></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p class="text-muted mb-0">
|
||||
<small>
|
||||
<i class="fas fa-fw fa-info-circle mr-1"></i>Run Now does not start the job in your browser - it asks the
|
||||
dispatcher to pick it up on its next pass, so a job starts within a minute and still runs on the command
|
||||
line with the same locking as a scheduled run. Detailed per-job output is in
|
||||
<a href="app_logs.php">App Logs</a>.
|
||||
</small>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once $_SERVER['DOCUMENT_ROOT'] . "/includes/footer.php"; ?>
|
||||
32
admin/database_updates/2.6.1.php
Normal file
32
admin/database_updates/2.6.1.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* ITFlow - Database update to version 2.6.1 (from 2.6.0)
|
||||
* Included by admin/database_updates.php - do not access directly
|
||||
*/
|
||||
|
||||
defined('FROM_DB_UPDATER') || die("Direct file access is not allowed");
|
||||
|
||||
// The cron dispatcher's schedule moves out of code and into the database so it can be
|
||||
// managed from Settings > Cron. The registry in includes/cron_jobs.php still decides
|
||||
// which scripts exist and seeds these columns the first time it meets a job; from then
|
||||
// on the row is what runs. Nothing here can name a script - a row whose job is not in
|
||||
// the registry is ignored.
|
||||
mysqli_query($mysqli, "ALTER TABLE `cron_jobs`
|
||||
ADD COLUMN `cron_job_enabled` tinyint(1) NOT NULL DEFAULT 1 AFTER `cron_job_name`,
|
||||
ADD COLUMN `cron_job_schedule` varchar(200) NOT NULL DEFAULT 'Interval' AFTER `cron_job_enabled`,
|
||||
ADD COLUMN `cron_job_interval_minutes` int(11) NOT NULL DEFAULT 1 AFTER `cron_job_schedule`,
|
||||
ADD COLUMN `cron_job_daily_at` time DEFAULT NULL AFTER `cron_job_interval_minutes`,
|
||||
ADD COLUMN `cron_job_run_now` tinyint(1) NOT NULL DEFAULT 0 AFTER `cron_job_daily_at`");
|
||||
|
||||
// Duration is here to make a job that is quietly getting slower visible before it starts
|
||||
// overrunning its own interval.
|
||||
mysqli_query($mysqli, "ALTER TABLE `cron_jobs`
|
||||
ADD COLUMN `cron_job_last_duration` decimal(10,2) DEFAULT NULL AFTER `cron_job_last_finished_at`,
|
||||
ADD COLUMN `cron_job_last_error` text DEFAULT NULL AFTER `cron_job_last_status`,
|
||||
ADD COLUMN `cron_job_last_error_at` datetime DEFAULT NULL AFTER `cron_job_last_error`");
|
||||
|
||||
// Written by the dispatcher every minute before it runs anything, so the admin page can
|
||||
// tell "no job happened to be due" apart from "the crontab entry is missing".
|
||||
mysqli_query($mysqli, "ALTER TABLE `settings`
|
||||
ADD COLUMN `config_cron_last_dispatch_at` datetime DEFAULT NULL");
|
||||
@@ -161,6 +161,12 @@
|
||||
|
||||
<li class="nav-header">MAINTENANCE</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="/admin/cron.php" class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'cron.php' ? 'active' : '') ?>">
|
||||
<i class="nav-icon fas fa-clock"></i>
|
||||
<p>Cron</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/admin/mail_queue.php" class="nav-link <?= (basename($_SERVER['PHP_SELF']) == 'mail_queue.php' ? 'active' : '') ?>">
|
||||
<i class="nav-icon fas fa-inbox"></i>
|
||||
|
||||
103
admin/modals/cron/cron_edit.php
Normal file
103
admin/modals/cron/cron_edit.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
require_once '../../../includes/cron_jobs.php';
|
||||
|
||||
$cron_job_id = intval($_GET['id']);
|
||||
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM cron_jobs WHERE cron_job_id = $cron_job_id LIMIT 1"));
|
||||
|
||||
$registry = cronJobRegistryByName();
|
||||
$job = $registry[$row['cron_job_name']] ?? null;
|
||||
|
||||
$cron_job_name = escapeHtml($row['cron_job_name']);
|
||||
$cron_job_label = escapeHtml($job['label'] ?? $row['cron_job_name']);
|
||||
$cron_job_enabled = intval($row['cron_job_enabled']);
|
||||
$cron_job_schedule = escapeHtml($row['cron_job_schedule']);
|
||||
$cron_job_interval_minutes = intval($row['cron_job_interval_minutes']);
|
||||
$cron_job_daily_at = escapeHtml(substr((string)$row['cron_job_daily_at'], 0, 5));
|
||||
|
||||
if (empty($cron_job_daily_at)) {
|
||||
$cron_job_daily_at = '03:00';
|
||||
}
|
||||
|
||||
// Generate the HTML form content using output buffering.
|
||||
ob_start();
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-clock mr-2"></i>Editing: <strong><?= $cron_job_label ?></strong></h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
||||
<input type="hidden" name="cron_job_id" value="<?= $cron_job_id ?>">
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="custom-control custom-switch">
|
||||
<input type="checkbox" class="custom-control-input" name="enabled" value="1" id="cronJobEnabledSwitch" <?= $cron_job_enabled == 1 ? 'checked' : '' ?>>
|
||||
<label class="custom-control-label" for="cronJobEnabledSwitch">Enabled</label>
|
||||
</div>
|
||||
<small class="text-muted">A disabled job never runs on its schedule, but Run Now still works.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Schedule</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
|
||||
</div>
|
||||
<select class="form-control" name="schedule" id="cronJobSchedule">
|
||||
<option value="Interval" <?= $cron_job_schedule === 'Interval' ? 'selected' : '' ?>>Every so many minutes</option>
|
||||
<option value="Daily" <?= $cron_job_schedule === 'Daily' ? 'selected' : '' ?>>Once a day</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="cronJobIntervalGroup">
|
||||
<label>Run every</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-redo"></i></span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="interval_minutes" value="<?= $cron_job_interval_minutes ?>" min="1" max="1440">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">minutes</span>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted">Cron wakes once a minute, so 1 is as often as anything can run.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="cronJobDailyGroup">
|
||||
<label>Run at</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-clock"></i></span>
|
||||
</div>
|
||||
<input type="time" class="form-control" name="daily_at" value="<?= $cron_job_daily_at ?>">
|
||||
</div>
|
||||
<small class="text-muted">Your ITFlow timezone. A run missed because the server was off happens at the next opportunity instead of waiting a day.</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="edit_cron_job" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function cronJobToggleScheduleFields() {
|
||||
var daily = document.getElementById('cronJobSchedule').value === 'Daily';
|
||||
document.getElementById('cronJobIntervalGroup').hidden = daily;
|
||||
document.getElementById('cronJobDailyGroup').hidden = !daily;
|
||||
}
|
||||
document.getElementById('cronJobSchedule').addEventListener('change', cronJobToggleScheduleFields);
|
||||
cronJobToggleScheduleFields();
|
||||
</script>
|
||||
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
130
admin/post/cron.php
Normal file
130
admin/post/cron.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
||||
|
||||
/*
|
||||
* Settings > Cron. Everything here identifies a job by its row, and every row is checked
|
||||
* against the registry in includes/cron_jobs.php before anything is written - the database
|
||||
* decides when and whether a job runs, never which file the dispatcher executes.
|
||||
*/
|
||||
|
||||
if (isset($_POST['edit_cron_job'])) {
|
||||
|
||||
validateCSRFToken();
|
||||
|
||||
require_once "../includes/cron_jobs.php";
|
||||
|
||||
$cron_job_id = intval($_POST['cron_job_id']);
|
||||
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT cron_job_name FROM cron_jobs WHERE cron_job_id = $cron_job_id LIMIT 1"));
|
||||
$registry = cronJobRegistryByName();
|
||||
|
||||
if (!$row || !isset($registry[$row['cron_job_name']])) {
|
||||
flashAlert("That cron job is not part of this version of ITFlow.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$cron_job_name = escapeSql($row['cron_job_name']);
|
||||
$enabled = isset($_POST['enabled']) ? 1 : 0;
|
||||
$schedule = $_POST['schedule'] === 'Daily' ? 'Daily' : 'Interval';
|
||||
|
||||
// A job cannot be asked to run more than once a minute (the dispatcher only wakes that
|
||||
// often) and anything over a day belongs on the daily schedule instead.
|
||||
$interval_minutes = min(1440, max(1, intval($_POST['interval_minutes'])));
|
||||
|
||||
// Time inputs hand back HH:MM; anything else is discarded rather than stored half-parsed
|
||||
$daily_at = 'NULL';
|
||||
if ($schedule === 'Daily') {
|
||||
$submitted = trim($_POST['daily_at']);
|
||||
if (!preg_match('/^([01][0-9]|2[0-3]):[0-5][0-9]$/', $submitted)) {
|
||||
flashAlert("Enter the daily run time as a 24-hour time, for example 03:00.", 'error');
|
||||
redirect();
|
||||
}
|
||||
$daily_at = "'" . escapeSql($submitted) . ":00'";
|
||||
}
|
||||
|
||||
mysqli_query($mysqli, "UPDATE cron_jobs SET
|
||||
cron_job_enabled = $enabled,
|
||||
cron_job_schedule = '$schedule',
|
||||
cron_job_interval_minutes = $interval_minutes,
|
||||
cron_job_daily_at = $daily_at
|
||||
WHERE cron_job_id = $cron_job_id");
|
||||
|
||||
logAudit("Cron", "Edit", "$session_name edited the schedule for cron job $cron_job_name", 0, $cron_job_id);
|
||||
|
||||
flashAlert("Cron job schedule updated.");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['run_cron_job'])) {
|
||||
|
||||
validateCSRFToken();
|
||||
|
||||
require_once "../includes/cron_jobs.php";
|
||||
|
||||
$cron_job_id = intval($_GET['run_cron_job']);
|
||||
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT cron_job_name FROM cron_jobs WHERE cron_job_id = $cron_job_id LIMIT 1"));
|
||||
$registry = cronJobRegistryByName();
|
||||
|
||||
if (!$row || !isset($registry[$row['cron_job_name']])) {
|
||||
flashAlert("That cron job is not part of this version of ITFlow.", 'error');
|
||||
redirect();
|
||||
}
|
||||
|
||||
$cron_job_name = escapeSql($row['cron_job_name']);
|
||||
$cron_job_label = $registry[$row['cron_job_name']]['label'];
|
||||
|
||||
// The job is not run here. These scripts are written for the command line and some of
|
||||
// them take minutes, so the request is left for the dispatcher to pick up on its next
|
||||
// pass, which also means it goes through the same lock and claim as a scheduled run.
|
||||
mysqli_query($mysqli, "UPDATE cron_jobs SET cron_job_run_now = 1 WHERE cron_job_id = $cron_job_id");
|
||||
|
||||
logAudit("Cron", "Run", "$session_name requested an immediate run of cron job $cron_job_name", 0, $cron_job_id);
|
||||
|
||||
flashAlert("$cron_job_label is queued and will start within a minute.");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['enable_cron_job']) || isset($_GET['disable_cron_job'])) {
|
||||
|
||||
validateCSRFToken();
|
||||
|
||||
$enabled = isset($_GET['enable_cron_job']) ? 1 : 0;
|
||||
$cron_job_id = intval($_GET[$enabled ? 'enable_cron_job' : 'disable_cron_job']);
|
||||
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT cron_job_name FROM cron_jobs WHERE cron_job_id = $cron_job_id LIMIT 1"));
|
||||
|
||||
if (!$row) {
|
||||
redirect();
|
||||
}
|
||||
|
||||
$cron_job_name = escapeSql($row['cron_job_name']);
|
||||
|
||||
mysqli_query($mysqli, "UPDATE cron_jobs SET cron_job_enabled = $enabled WHERE cron_job_id = $cron_job_id");
|
||||
|
||||
logAudit("Cron", "Edit", "$session_name " . ($enabled ? 'enabled' : 'disabled') . " cron job $cron_job_name", 0, $cron_job_id);
|
||||
|
||||
flashAlert("Cron job " . ($enabled ? 'enabled' : 'disabled') . ".", $enabled ? 'success' : 'error');
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['clear_cron_error'])) {
|
||||
|
||||
validateCSRFToken();
|
||||
|
||||
$cron_job_id = intval($_GET['clear_cron_error']);
|
||||
|
||||
mysqli_query($mysqli, "UPDATE cron_jobs SET cron_job_last_error = NULL, cron_job_last_error_at = NULL WHERE cron_job_id = $cron_job_id");
|
||||
|
||||
flashAlert("Error cleared.");
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user