클라이언트에서 특정 위치에 도착했을 때 POST를받는 laravel 5.2 앱이 있습니다. 경우에 따라 클라이언트는 동시에 두 개의 동일한 요청을 실행하지만 동일한 레코드 (이러한 중복 요청에 포함되지 않은 마지막 이벤트)를 사용하여 처리 방법을 결정합니다.Laravel 동시 쓰기 방지
각 요청에 대해 클라이언트가 이미 해당 사용자의 마지막 이벤트를 확인하여 동일한 위치에 로그인했는지 여부를 확인하여 중복 체크 인/체크 아웃을 방지하려고합니다.
예 :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Checkin;
use App\Models\Population;
use App\Http\Requests;
class CheckinApiController extends Controller {
public function post(Request $request) {
$uuid = $request->uuid;
$isCheckin = $request->isCheckin;
$locationId = $request->locationId;
// get the last checkin for user matching this UUID
$lastCheckin = Checkin::where("uuid", $uuid)
->orderBy('updated_at', 'desc')
->first();
if ($isCheckin == $lastCheckin->isCheckin
&& $locationId == $lastCheckin->locationId) {
/* Scenario 1:
* if this post event is the same as the last record's checkin type
* (checkin/checkout), and the locationIds are the same, this is a
* duplicate. Return an error code and message
* In this case, both the duplicate requests see the same record,
* and both are handled as duplicates
*/
abort(403, 'duplicate');
} else if ($isCheckin == true
&& $isCheckin == $lastCheckin->isCheckin
&& $locationId != $lastCheckin->locationId) {
/* Scenario 2:
* this is a checkin event, but the last event for this user was
* a checkin at a different location
* we create a mock 'checkout' for this request, and
* set the updated_at field as current time minus a few seconds
* BUT... in the case of duplicates, both duplicates see the
* last event, so both duplicates handle this the same way, and i
* get TWO $missedCheckin records.
*/
$missedCheckin = Checkin::create([
'locationId' => $lastCheckin->locationId,
'isCheckin' => false,
'uuid' => $uuid,
'updated_at' => time() - 10,
]);
}
// write this checkin event
$checkin = Checkin::create([
'locationId' => $locationId,
'isCheckin' => $isCheckin,
'uuid' => $uuid
]);
// adjust population on another model
$population = Population::firstOrCreate([
'location_id' => $locationId
]);
// increment or decrement population based on
// if this is a checkin or checkout,
// omitted here but mentioned as it is another
// database transaction on a different model
// $responseDataSet is a dictionary with info to tell the client to present to the user
return response()->json($responseDataSet);
}
}
내가 가능한 복제를 일시 중단 할 수있는 방법은, 첫 번째 레코드는이 절차를 통해, 오직 다음 두 번째 사람이 통과 할 수 있도록이 허용인가 (으로 볼 것이다 중복)?
는 내가 처리하기 전에 밀리 초 단위의 임의의 숫자를 기다려야 다음에 넣어려고했는데, 난수 생성기가 동일한 요청시 같은 난수를 반환 것으로 보인다 :$msToSleep = 1 * random_int(500, 100000);
usleep($msToSleep);
클라이언트는하지 않습니다 필연적으로 결과를 알고 있어야하므로 200 개의 상태 코드 이외의 값을 반환 할 필요는 없습니다. 그러나 결국에는 생성 된 유효한 체크인 객체를 반환하려고 할 수 있습니다.
그러나 나는 $ lastCheckin이 제대로 처리 된 복제본의 결과 인 $ lastCheckin을 볼 수있는 중복 요청 집합의 두 번째 요청이 필요합니다 (때로는 중복 일 수도 있지만 몇 분으로 분리됨). 그리고 처리되었습니다. 따라서.
사용자가 어떻게 두 가지 이벤트를 발생 시키나요? 클라이언트 측에서이를 막기가 더 쉽지 않을까요? – James
잘 모르겠습니다. 이것을 추적하려고합니다. 그들은 백그라운드 업데이트, 비동기 스레드에서 위치 업데이트 및 체크 인 이벤트에 응답합니다. –
해결할 문제를 해결하기보다는 루트 문제를 해결할 것입니다. – James