Я здесь для тебя
Для очень-очень многих проектов нет экономического оправдания использования многих технологий и кажется что чем проще, тем лучше. SQLite предоставляет для разработчика очень простой механизм, не нужно ни настраивать пользователей, ни защищать сетевой подключение, ни обслуживать процессы, только файл в котором будет хранится данные. Что может быть проще?
По этому не удивительно, что SQLite в последнее время набирает популярность не только на локальных устройствах, но в веб приложениях, например Rails 7.1 поставляется с настроенной SQLite базой по умолчанию и с новым оптимизированным драйвером. А начиная с Laravel 11.x так же будет поставляется с SQLite по умолчанию, так как это самый простой способ начать работать и запуститься в производство.
Как и у любой базы данных есть свои особоенности и скорее всего вы познакомитесь с ними когда будете выполнять миграции и локальную разработку. По этому давайте сосредоточимся на том, что бы подготовит базу данных для работы с Laravel в производственной среде.
По умолчанию SQLite может либо читать данные, либо записывать, но не оба действия одновременно. Если в вашем проекте соотношение чтения к записи намного больше, то это совсем не проблема.
В противном случае включите режим упреждающей записи (WAL) командой:
sqlite3 database.sqlite "PRAGMA journal_mode = wal"
Этот шаг переведет вашу базу данных в режим WAL, что позволит ей эффективно обрабатывать одновременные операции чтения и записи. Вы можете убедиться в этом, выполнив следующую команду:
sqlite3 database.sqlite "PRAGMA journal_mode"
Если результатом является wal
, это означает, что база данных успешно переведена в режим предварительной записи.
По умолчанию SQLite физичиски не удаляет данные, по этому размер файла может сильно расти, что бы осовободить неиспользуемое дисковое пространство необходимо выполнить команду vacuum:
sqlite3 database.sqlite "PRAGMA vacuum;"
Перед выполнением база данных будет автоматически скопирована, чтобы избежать блокировки работы приложения. Однако это означает, что для выполнения операции потребуется свободное дисковое пространство, превышающее размер исходной базы данных в два раза.
Чтобы добиться наилучшей долгосрочной производительности запросов без необходимости проведения детального технического анализа схемы необходимо выполнять команду оптимизации:
sqlite3 database.sqlite "PRAGMA optimize;"
Лучше всего выполнять эту команду с переодичностью, например каждый час.
По умолчанию SQLIte синхронизирует журнал отказа после каждого запроса на изменение, что бы гарантировать, что весь контент безопасно записан на диск, однако это не всегда необходимо, можно изменить этот режим выполнив первым запросом в соединении:
sqlite3 database.sqlite "PRAGMA synchronous = normal;"
Это будет иметь эффект только на конкретное соединение, по этому вам скорее всего потребуется внести изменения в ваш код.
Теперь, когда мы ознакомились с этими командами, настало время внедрить их в наше приложение на Laravel для максимального удобства. Например, вместо настройки новых задач на уровне сервера, сделать это на уровне приложения:
$schedule->command('sqlite:optimize')->everyMinute();
$schedule->command('sqlite:vacuum')->daily();
Cпециально для этих целей создал пакет небольшой Composer, который позволяет вызывать каждую из них легко с помощью Artisan:
Не стесняйтесь присоединиться к развитию проекта и делиться своим опытом использования!
Я здесь для тебя
Когда что-то не срабатывает с первого раза, что мы делаем? Правильно, пробуем снова. Вдруг на этот раз получится? Этот же подход хорошо работает и в разработке.
Мы можем повторять неудачные операции, чтобы восстановиться после временных ошибок или сбоев в сети. Laravel предоставляет “из коробки” набор отличных механизмов “повтора” для обработки временных сбоев!
Перечисленные методы ни как не помогут со сбоями вызванной неправильной бизнес-логикой, ошибками в коде, или неверными данными (
.env
). Независимо от того, сколько раз мы их повторяем, эти сбои не будут автоматически исправлены, пока мы не исправим код или конфигурацию.
Теперь давайте узнаем о механизмах “Повтора” в Laravel:
При выполнении транзакции базы данных может возникнуть взаимоблокировка. Это может произойти, когда транзакция не может завершиться из-за конфликта с другой параллельной транзакцией, пытающейся записать те же данные.
В методе DB::transaction
можно просто передать второй параметр, чтобы указать, сколько раз он будет повторять транзакцию, если произойдет взаимоблокировка.
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::update('update users set votes = 1');
DB::delete('delete from posts');
}, 5);
Подробнее можно посмотреть в документации:
Мы все знаем, что сторонние API или сервисы не всегда надежны! По этому должны построить наше приложение так, чтобы мы могли элегантно обрабатывать сбои этих сервисов.
Если мы используем HTTP Client
, предоставленный Laravel, мы можем использовать метод retry
, чтобы автоматически повторить вызов API, если он не был успешным.
$response = Http::retry(3, 100)->post(/* ... */);
Мы также можем передать второй параметр методу, чтобы указать, сколько времени Laravel должен подождать перед повторной попыткой.
Хорошей идеей является ожидание некоторого времени перед повторной попыткой. Потому что, если сервис недоступен, мгновенная повторная попытка также может завершиться неудачей.
Подробнее можно посмотреть в документации:
При выполнении задания в очереди оно может не выполниться из-за какой-то ошибки. Если сбой вызван временными ошибками, хорошей идеей будет попытаться выполнить задание снова.
При запуске queue:work
мы можем передать аргумент для указания максимального количества попыток выполнения задания, если оно не удалось.
php artisan queue:work --tries=3
А так же можем указать в каждом задании отдельно, сколько раз оно может быть повторено, и сколько времени оно должно ожидать перед повтороной попыткой:
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* Количество попыток выполнить задание.
*
* @var int
*/
public $tries = 5;
/**
* Количество секунд ожидания перед повторной попыткой задания.
*
* @var int
*/
public $backoff = 3;
}
Мы также можем определить метод tries
, метод backoff
или использовать подход на основе времени, определив метод retryUntil
в классе задания.
Подробнее можно посмотреть в документации:
Даже после нескольких попыток выполнить задание некоторые из них могут остаться неудачными из-за ошибок, для исправления которых нужно внести изменения в код или конфигурацию. Laravel сохраняет такие неудавшиеся задания в специальной таблице базы данных failed_jobs
, что бы после изменений мы могли повторно выполнить задания.
С помощью команды php artisan queue:retry
мы можем повторно выполнить как одно, несколько или все задания.
Подробнее можно посмотреть в документации:
Laravel предоставляет отличный вспомогательную функцию под названием retry
, который можно использовать для повтора любого участка кода. Это действительно полезно, когда мы хотим повторить какую-то логику с разными параметрами.
Вот простой пример для генерации уникального числа, которое еще не используется на основе некоторых критериев:
function getUniqueNumber()
{
return retry(5, function () {
$number = rand(1, 100);
// 'isUsed' - вымышленный метод, который проверяет какую-то логику
if (isUsed($number)) {
throw new Exception('Число уже используется');
}
return $number;
});
}
Подробнее можно посмотреть в документации:
Хотя это не является частью механизма повтора, но заслуживает упоминания.
При запуске php artisan down
мы также можем указать параметр retry
, который будет установлен как значение заголовка HTTP Retry-After
:
php artisan down --retry=60
Некоторые браузеры будут автоматически обновлять страницу с указанным интервалом, освобождая пользователя от необходимости постоянно нажимать “F5”.
Подробнее можно посмотреть в документации:
{message}