Cron Lock Manager
Prevents overlapping cron/maintenance jobs with expiring locks.
Function signature
ogAcquireCronLock(lock_file, ttl_seconds = 900, owner = '')
Categories
- Maintenance and Cron
Parameters
lock_fileApproved filesystem path for the cron lock file.ttl_secondsMaximum lock lifetime in seconds before a stale lock can be reviewed.ownerLog-safe owner label for the process or request attempting the lock.Return value
Public-safe status string returned by the function for explicit controller branching or logging.
- success
- message
- data
Compatibility
Existing function name, slug, path, and call order preserved; advertised metadata corrected to the actual source behavior.
Minimum PHP version: 7.4
Security notes
Use caller-owned allowlists and context-specific escaping; validate admin actions, export fields, privacy plans, cache keys, templates, settings, routes, and ecommerce policies before production use.
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Prevents overlapping cron/maintenance jobs with expiring locks.
*
* Primary use case: Imports, cleanup, emails, sitemap generation.
* Typical inputs: job key, ttl, storage backend.
* Typical output: lock result.
*
* Implementation note: Release locks safely and expire stale locks.
*
* @param string $lock_file Approved lock-file path.
* @param int $ttl_seconds Lock lifetime in seconds.
* @param string $owner Optional owner label.
* @return array Lock acquisition result.
*/
function ogAcquireCronLock($lock_file, $ttl_seconds = 900, $owner = '') {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
$lock_file = trim((string)$lock_file);
$ttl_seconds = (int)$ttl_seconds;
$owner = trim((string)$owner);
if (empty($lock_file)) {
$result['message'] = 'Lock file is required.';
return $result;
}
if ($ttl_seconds < 60) {
$ttl_seconds = 60;
}
$directory = dirname($lock_file);
if (!is_dir($directory) || !is_writable($directory)) {
$result['message'] = 'Lock directory is not writable.';
return $result;
}
$existing = array();
if (is_file($lock_file)) {
$raw = file_get_contents($lock_file);
$decoded = json_decode((string)$raw, true);
if (is_array($decoded)) {
$existing = $decoded;
}
}
$now = time();
if (!empty($existing['expires_at']) && (int)$existing['expires_at'] > $now) {
$result['message'] = 'Cron lock is already active.';
$result['data'] = array('acquired' => false, 'expires_at' => (int)$existing['expires_at']);
return $result;
}
$lock_data = array(
'owner' => $owner,
'pid' => getmypid(),
'created_at' => $now,
'expires_at' => $now + $ttl_seconds
);
$written = file_put_contents($lock_file, json_encode($lock_data), LOCK_EX);
if ($written === false) {
$result['message'] = 'Unable to write cron lock.';
return $result;
}
$result['success'] = true;
$result['message'] = 'Cron lock acquired.';
$result['data'] = array('acquired' => true, 'lock_file' => $lock_file, 'expires_at' => $lock_data['expires_at']);
return $result;
}