Несколько запросов одновременно обходят проверки - PullRequest
0 голосов
/ 28 мая 2018

В основном у меня есть онлайн-игра, построенная на PHP (Laravel).Это функциональность довольно проста.Когда игрок экипирует предмет, он проверяет, экипирован ли предмет того же типа.Если нет экипированного предмета того же типа, он будет идти дальше и экипировать предмет.

Это можно сделать, просто установив флаг экипировки на модели инвентаря равным 1. Что-то вроде этого

        if($alreadyequippeditem == false){
        //equip current item
        $inventory = \App\Inventory::find($item->pivot->id);
        $inventory->equipped = 1;
        $inventory->save();
        }

Однако, если сделать это достаточно быстро, человек может экипировать два (или даже больше) предмета одновременно в одно и то же время.По сути, в обход проверки.

Мне кажется, что два запроса обрабатываются сервером в одно и то же время, и они оборудуют элементы в одно и то же время, и это по существу обходит проверки.Это может объяснить, почему два предмета могут быть оборудованы, потому что во время выполнения запросов они не распознают друг друга.Я могу ошибаться, но это единственное объяснение, которое я могу придумать.

Как я могу обойти это?Есть ли способ ограничить его, чтобы одновременно отправлялся только 1 запрос?Я не могу вспомнить, чтобы когда-либо сталкивался с этой проблемой, когда я создавал системы с ядром PHP и без фреймворка, поэтому я понятия не имею, вызвано ли это какой-то конфигурацией laravel.Я понимаю, что, возможно, смогу обойти это, используя очереди (хотя я не особо разбирался в этом), но я бы предпочел найти решение, которое работает по всему сайту, поскольку эта конкретная проблема затрагивает многие области системы.

1 Ответ

0 голосов
/ 28 мая 2018

Проблема (условие гонки)

То, что вы испытываете, является примером классического учебника условия гонки :

Состояние гонки - этоНежелательная ситуация, которая возникает, когда устройство или система пытается выполнить две или более операций одновременно, но из-за природы устройства или системы, операции должны выполняться в правильной последовательности для правильного выполнения.

Пример исправления со всеми необходимыми вещами

К счастью для нас, это не новая проблема и не очень сложная для решения.Особенно при использовании Laravel:

<?php
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Inventory;
use App\Player;
use Request;


class BustRaceConditionsController extends Controller
{
    public function EquipItem(Request $request)
    {
        \DB::beginTransaction();

        $player = $player->where("id", $request->user()->player_id)->lockForUpdate()->first();

        $success = true;

        try {

            /* some logic here to check if item is equiped or not */

            if (itemIsEquiped()) {

                $success = false;

            } else {

                /* lets equip the item, then save it, and then we need to commit it to the DB */

                $player->itemEquip = $item;
                $player->save();

                \DB::commit();

            }


        } catch (\Exception $e) {

            $success = false;
            \DB::rollback();

        }
        return ['success' => $success];
    }
}
  1. Это очень грубый пример того, как это делается в Laravel, но, по сути, здесь происходит то, что мы запускаем транзакцию БД , котораяпозволяет нам убедиться, что все работает или ничего не работает.Это особенно полезно в этой ситуации.
  2. Далее мы собираем все данные, которые хотим получить из модели, но обратите внимание, что я использую lockForUpdate() в цепочке методов.Это сделано для того, чтобы ничто иное не могло читать или писать до тех пор, пока мои изменения не будут зафиксированы или завершатся с ошибкой, и, таким образом, снимет блокировку.
  3. Наконец, нам нужно либо зафиксировать изменение в БД, либо, в конечном счете, потерять изменение иоткатить все назад.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...