Команда Laravel выпустила версию 13.38.0, в которой появились middleware PreventStaleDatabaseReads для приложений, читающих данные из реплик базы данных, метод usingWritePdo() , направляющий все операции чтения внутри callback-функции на соединение для записи, маршрут проверки работоспособности (health route), работающий с кэшированными маршрутами на разных машинах, и многое другое.
#Middleware PreventStaleDatabaseReads
Jack Bayliss добавил опциональное middleware для приложений с разделенными соединениями для чтения и записи базы данных. Реплика может отставать от сервера записи, поэтому пользователь, сохранивший изменения и перезагрузивший страницу, может увидеть старые данные.
После того как запрос выполняет запись в соединение базы данных по умолчанию, middleware сохраняет временную метку в сессии. В течение следующих двух секунд операции чтения этого пользователя направляются на соединение для записи. После этого чтение снова переключается на реплики. Вы можете добавить его в группу web :
use Illuminate\Foundation\Http\Middleware\PreventStaleDatabaseReads;
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
PreventStaleDatabaseReads::class,
]);
})
Или применить его к группе маршрутов с более длительным окном:
Route::middleware(PreventStaleDatabaseReads::for(10))->group(function () {
Route::get('/posts/{post}', [PostController::class, 'show']);
Route::put('/posts/{post}', [PostController::class, 'update']);
});
Middleware требует наличия сессии и отслеживает только соединение по умолчанию. Оно охватывает только того пользователя, который выполнил запись, поэтому другие пользователи по-прежнему могут видеть старые данные из реплики.
Подробности см. в #62078.
#DB::usingWritePdo()
Jack Bayliss также добавил usingWritePdo() в соединение с базой данных. Существующий метод onWriteConnection() применяется только к тому запросу, который он запускает, поэтому связь (relationship), загруженная из результата, все равно будет считываться из реплики:
// The posts query still runs on a replica
$posts = User::onWriteConnection()
->where('email', $email)
->first()
?->posts()
->whereNull('published_at')
->get();
Новый метод направляет все операции чтения внутри callback-функции на соединение для записи, а затем восстанавливает предыдущие настройки, даже если callback вызывает исключение:
$posts = DB::usingWritePdo(fn () => User::query()
->where('email', $email)
->first()
?->posts()
->whereNull('published_at')
->get()
);
Подробности см. в #62099.
#CountCrashesAsExceptions для слушателей, mailable-классов и уведомлений
Dennis Petersmann сделал так, чтобы атрибут #[CountCrashesAsExceptions] , появившийся в Laravel 13.34, работал с поставленными в очередь слушателями (queued listeners), mailable-классами и уведомлениями. До этого релиза он работал только с заданиями (jobs).
Для остальных трех типов, если воркер падал (например, из-за нехватки памяти), это не учитывалось в maxExceptions , поэтому слушатель или письмо перезапускались без ограничений, когда $tries был равен 0 :
#[MaxExceptions(3), CountCrashesAsExceptions]
class ExportOrders implements ShouldQueue
{
public $tries = 0;
public function handle(OrdersImported $event)
{
// ...
}
}
Подробности см. в #62048.
#Атрибут соединения дочерней модели переопределяет унаследованное соединение
Volodya Kurshudyan исправил ошибку, из-за которой модели игнорировали атрибут #[Connection] , если родительский класс устанавливал свойство $connection . Запросы для дочерней модели уходили на соединение родителя без каких-либо ошибок:
abstract class BaseModel extends Model
{
protected $connection = 'mysql';
}
#[Connection('reporting')]
class SalesReport extends BaseModel {}
(new SalesReport)->getConnectionName(); // Now returns "reporting"
Подробности см. в #62065.
#Исправления для уникальных заданий (Unique Jobs)
Sumaia Aktar исправила проблему, при которой уникальные задания, запланированные с помощью Schedule::job() , сохраняли свою блокировку при неудачной попытке отправки в очередь. При значении uniqueFor по умолчанию, равном 0 , блокировка никогда не истекала, поэтому планировщик пропускал задание при каждом последующем запуске, даже после того, как очередь снова начинала работать. Теперь планировщик снимает блокировку и повторно выбрасывает исключение. В Laravel 13.37 аналогичное изменение было сделано для dispatch() и поставленных в очередь слушателей. См. #62083.
Jack Bayliss также сделал так, чтобы широковещательные события (broadcast events), реализующие ShouldBeUnique , отправляли событие UniqueJobSkipped при пропуске, так же как это делают поставленные в очередь задания. См. #62077.
#Снижение потребления памяти в lazy() и lazyById()
Volodya Kurshudyan изменил lazy() и lazyById() так, чтобы они освобождали предыдущий чанк (chunk) перед выборкой следующего. До этого изменения в памяти одновременно удерживались два чанка, поэтому пиковое потребление памяти было примерно в два раза выше необходимого. Методы chunk() и chunkById() уже работали таким образом.
Подробности см. в #62086.
#Примечания к выпуску
Полный список новых функций и обновлений вы можете увидеть ниже, а также сравнение изменений (diff) между 13.37.0 и 13.38.0 на GitHub. Следующие примечания к выпуску взяты непосредственно из changelog:
#v13.38.0
- [13.x] Разрешить значения float в правиле Unique
whereот @sertxudev в #62059 - [13.x] Удалить неиспользуемый прокси-объект
untilhigher order collection от @xurshudyan в #62057 - [13.x] Исправить псевдоним ofMany() внутри замыканий от @xurshudyan в #62051
- [13.x] Исправить запросы на существование и агрегатные запросы для самоссылающихся отношений one-of-many от @xurshudyan в #62043
- [13.x] Поддержка CountCrashesAsExceptions для поставленных в очередь слушателей, mailable-классов и уведомлений от @Taldres в #62048
- [13.x] Сделать маршрут проверки работоспособности совместимым с кэшированием маршрутов на разных машинах от @percymamedy в #62049
- [13.x] Восстановить неймспейс для Cloud logging formatter от @xurshudyan в #62068
- [13.x] Запустить интеграционные тесты для Memcached cache lock и tagged cache от @xurshudyan в #62069
- [13.x] Исправить
mode(), возвращающий обрезанные значения для float от @xurshudyan в #62063 - [13.x] Сбрасывать флаг
NotificationFailedперед каждой отправкой канала от @xurshudyan в #62074 - [13.x] Учитывать дочерний атрибут
#[Connection]вместо унаследованного свойства$connectionот @xurshudyan в #62065 - [13.x] Исправить
whereBetweenиwhereNotBetweenс границами коллекции от @xurshudyan в #62062 - [13.x] Исправить изменение таблиц SQLite с внешним ключом на имя таблицы, требующее кавычек от @sumaiazaman в #62084
- [13.x] Исправить clone() для отношений от @xurshudyan в #62081
- [13.x] Освобождать уникальную блокировку при сбое отправки запланированного задания от @sumaiazaman в #62083
- [13.x] Исправить некорректные docblocks от @xurshudyan в #62097
- [13.x] Исправить ошибку PHPStan при передаче замыкания в PendingBatch::allowFailures() от @xurshudyan в #62096
- [13.x] Удалить неиспользуемые импорты от @xurshudyan в #62087
- [13.x] Освобождать предыдущий чанк в
lazy()иlazyById()от @xurshudyan в #62086 - [13.x] Добавить middleware PreventStaleDatabaseReads от @jackbayliss в #62078
- [13.x] Отправлять UniqueJobSkipped при пропуске уникального широковещательного события от @jackbayliss в #62077
- [13.x] Удалить неиспользуемые файлы тестов от @xurshudyan в #62101
- [13.x] Исправить TypeError в правилах сравнения дат для значений, не являющихся датами от @GrahamCampbell в #62103
- [13.x] Исправить некорректные docblocks от @xurshudyan в #62100
- [13.x] Добавить usingWritePdo в Connection от @jackbayliss в #62099
Комментарии (0)
Пока нет комментариев — будьте первым.