При использовании персональных токенов доступа 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.
