При использовании персональных токенов доступа Sanctum для API аутентификации, я заметил, что часть входящих запросов, выполняются раз в 5-10 дольше, чем другие. Покопавшись я обнаружил, что при каждом запросе Sanctum обновляет поле last_used_at
в таблице personal_access_tokens
. Большинство запросов всё же выполнялись быстро, но мере увеличения их объёма, некоторые начинали тормозить.
Не я первый это заметил, но пока нет простого способа это отключить.
Решение
В проекте мне была не нужна информация о последнем использовании токена, поэтому, чтобы её убрать я создал модель PersonalAccessToken
с методом save()
, который проверяет изменено ли только поле last_used_at
.
Сначала, с помощью artisan-команды я создал новую модель:
php artisan make:model PersonalAccessToken
Затем внутри модели я использовал следующий код:
namespace App; use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken; class PersonalAccessToken extends SanctumPersonalAccessToken { /** * Ограничение сохранения записей PersonalAccessToken * * Будет сохранять, только если изменилось * что-то кроме поля last_used_at. * Это предотвратит лишние записи в БД, * так как мы нее используем это поле. * * @param array $options * @return bool */ public function save(array $options = []) { $changes = $this->getDirty(); // Проверяем два изменения, так как одно из них это всегда поле updated_at if (! array_key_exists('last_used_at', $changes) || count($changes) > 2) { parent::save(); } return false; } }
Наша кастомная модель расширяет модель из Sanctum и имеет всего лишь один метод save()
.
Она получает все изменённые значения и проверяет будет ли сохранятся что-то кроме last_used_at
. Если да, то оно вызывает родительский метод save()
из Sanctum. В противном случае просто возвращается false
, который указывает, что сохранения не было.
После создания кастомной модели нам нужно задать её использование вместо дефолтной. Сделать это можно в методе boot()
класса Providers/AppServiceProvider.php
. В Sanctum есть статический метод usePersonalAccessTokenModel()
, который можно использовать для задания модели для токенов.
Выглядеть это будет примерно так:
/** * Bootstrap any application services. * * @return void */ public function boot() { // Используем нашу модель для токенов Sanctum::usePersonalAccessTokenModel( PersonalAccessToken::class ); }
После этого я сразу же заметил прирост производительности, так как запись в БД это дорогая операция, особенно если вы используете репликацию и разделение чтение/записи.
Автор: William Earnhardt
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.