Настройка cron-задач для веб-приложения
Cron-задачи запускают код по расписанию: очистка устаревших данных, отправка дайджестов, генерация отчётов, обновление кэша. Главная задача при настройке — исключить параллельный запуск одной задачи и обеспечить мониторинг выполнения.
Laravel Task Scheduling
// app/Console/Kernel.php
protected function schedule(Schedule $schedule): void
{
// Ежедневный дайджест в 9:00 по Москве
$schedule->job(SendDailyDigestJob::class)
->dailyAt('09:00')
->timezone('Europe/Moscow')
->withoutOverlapping() // не запускать если предыдущий ещё работает
->onOneServer() // только на одном сервере при горизонтальном масштабировании
->runInBackground();
// Очистка устаревших сессий — каждый час
$schedule->command('sessions:cleanup')
->hourly()
->withoutOverlapping(5) // максимум 5 минут на перекрытие
->appendOutputTo(storage_path('logs/sessions-cleanup.log'));
// Ежеминутная проверка очереди уведомлений
$schedule->command('notifications:send-pending')
->everyMinute()
->runInBackground()
->skip(fn() => !config('features.notifications'));
// Отчёт по понедельникам в 8:00
$schedule->job(WeeklyReportJob::class)
->weekly()
->mondays()
->at('08:00');
}
# Crontab: запускать планировщик каждую минуту
* * * * * cd /var/www/myapp && php artisan schedule:run >> /dev/null 2>&1
Node.js: node-cron
import cron from 'node-cron';
import { db } from './database';
import { emailService } from './services/email';
// Ежедневная очистка в 3:00
cron.schedule('0 3 * * *', async () => {
const lock = await acquireLock('cleanup-expired-tokens');
if (!lock) return; // другой инстанс уже выполняет
try {
const deleted = await db.query(
'DELETE FROM password_reset_tokens WHERE expires_at < NOW()'
);
console.log(`Cleaned ${deleted.rowCount} expired tokens`);
} finally {
await releaseLock('cleanup-expired-tokens');
}
}, { timezone: 'Europe/Moscow' });
// Каждые 5 минут: обновление курсов валют
cron.schedule('*/5 * * * *', async () => {
try {
const rates = await fetchExchangeRates();
await cache.set('exchange_rates', rates, 300);
} catch (err) {
console.error('Exchange rates update failed:', err);
}
});
Distributed Lock через Redis (предотвращение дублирования)
// Для Laravel: стандартный Cache::lock()
$schedule->call(function () {
$lock = Cache::lock('daily-digest', 3600);
if (!$lock->get()) {
return; // другой сервер уже выполняет
}
try {
app(DigestService::class)->sendAll();
} finally {
$lock->release();
}
})->dailyAt('09:00')->onOneServer();
Мониторинг: Healthchecks.io / Laravel Health
# Crontab с ping-уведомлением
* * * * * cd /var/www/myapp && php artisan schedule:run \
&& curl -fsS https://hc-ping.com/YOUR-UUID > /dev/null 2>&1
// Уведомление об ошибках планировщика
$schedule->job(SendDailyDigestJob::class)
->dailyAt('09:00')
->pingOnSuccess('https://hc-ping.com/success-uuid')
->pingOnFailure('https://hc-ping.com/fail-uuid')
->emailOutputOnFailure('[email protected]');
Срок реализации
Настройка cron-расписания для Laravel или Node.js приложения: 1 день. С distributed lock, мониторингом выполнения и алертами: 2 дня.







