@Ad4ptec

Как обработать запрос в Laravel Octane в одном потоке?

Стек: Laravel 9.26, Octane 1.3, Swoole 4.8.5, MariaDB 10.7

Есть следующая проблема:
Во время отправки параллельных запросов данные могут измениться несколько раз вне зависимости от проверки наличия этих данных в БД. Другими словами если к примеру эмулировать 5 одновременных запросов на 1 метод - то код может выполнится столько раз - сколько свободных потоков в Octane, при том проверка на созданную запись в коде не проходит корректно и создается дублирующая запись.

Приведу пример, есть контроллер в котором есть функция для создания лайка на запись:
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller
{
    public function like(Request $request)
    {
        $request->validate([
            'uuid' => 'required',
        ]);

        $user = $request->user();

        $post = Post::whereUuid($request->uuid)->first();
        abort_if(!$post, 404);

        if (!$post->likes()->whereAccountId($user->id)->exists()) {
            $post->likes()->attach($user);
        }

        $post->loadCount(['likes']);

        return response()->json([
            'ok' => true,
            'likes_count' => $post->likes_count,
        ]);
    }

}


Роут:
Route::post('post/like', [\App\Http\Controllers\PostController::class, 'like']);


На js выполняю 5 запросов в цикле, после чего может сохраниться от 1 до 4 лайков в БД (смотря сколько потоков запущено для Octane)

Подскажите, пожалуйста, как можно решить данную проблему, чтобы конкретный код не выполнялся в многопоточном режиме?
  • Вопрос задан
  • 170 просмотров
Решения вопроса 1
iMedved2009
@iMedved2009
Не люблю людей
Операция проверить есть запись и вставить - не атомарная. У вас одновременно может выполнится вагон проверок и начать вставку.

1. Использовать локи. Залочили таблицу, проверили, вставили, убрали лок.

2. Повесить unique на связку поле ['user_id', 'post_id'], и через catch ловить нужный exception.

3. Повесить unique на связку поле ['user_id', 'post_id'], и добавить макро upsert - на вставку pivot.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы