Идемпотентный агент с блокировкой (lock file/DB)
Шаблон агента или cron-задачи с защитой от параллельного запуска через файловую блокировку или DB lock.
Как использовать
- Скопируйте нужный фрагмент кода.
- Вставьте в свой проект и при необходимости измените под задачу.
- Проверьте зависимости и окружение (версии, переменные).
Защищает агента от параллельного запуска через файловую блокировку или блокировку в БД. Используйте для долгих задач, которые не должны выполняться одновременно.
use Bitrix\Main\Application;
use Bitrix\Main\DB\Connection;
/**
* Идемпотентный агент с файловой блокировкой
*/
function MyAgentTask() {
$lockFile = $_SERVER['DOCUMENT_ROOT'] . '/upload/locks/my_agent.lock';
$lockHandle = @fopen($lockFile, 'w');
if (!$lockHandle) {
return "MyAgentTask();"; // Не удалось создать lock, пропускаем
}
// Пытаемся получить эксклюзивную блокировку (non-blocking)
if (!flock($lockHandle, LOCK_EX | LOCK_NB)) {
fclose($lockHandle);
return "MyAgentTask();"; // Уже выполняется, пропускаем
}
try {
// Ваша логика агента
// ...
// Симулируем работу
sleep(5);
} finally {
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
@unlink($lockFile); // Опционально: удаляем lock файл
}
return "MyAgentTask();"; // Повторный запуск
}
/**
* Альтернатива: блокировка через БД (для кластера)
*/
function MyAgentTaskWithDBLock() {
$connection = Application::getConnection();
$lockName = 'my_agent_lock';
$lockTimeout = 300; // 5 минут
// Пытаемся получить блокировку (MySQL GET_LOCK)
$result = $connection->query("SELECT GET_LOCK('{$lockName}', {$lockTimeout}) as lock_acquired")->fetch();
if (!$result || !$result['lock_acquired']) {
return "MyAgentTaskWithDBLock();"; // Не удалось получить lock
}
try {
// Ваша логика
// ...
} finally {
// Освобождаем блокировку
$connection->query("SELECT RELEASE_LOCK('{$lockName}')");
}
return "MyAgentTaskWithDBLock();";
}
Usage:
Зарегистрируйте агента через CAgent::AddAgent() или в админке. Lock файл создастся автоматически при первом запуске.
Notes:
⚠️ Для кластеров используйте DB lock (GET_LOCK). Файловый lock работает только на одной ноде. Убедитесь, что папка /upload/locks/ существует и доступна для записи.