こんにちは、さるまりんです🐵
今回はいつもより具体的な記事です。
Laravelで「カートが処理中の間は他の操作をブロックしたい」というときに使えるコードをまとめてみました。
APIでカートの注文確定などの処理を行っていて、ユーザーが別画面でカートをいじってしまうと、データがおかしくなったり、意図しない動作になることがあります。
そんな時にLaravelのCache
を使って「カートにロックをかける」方法を試してみました。
こんな場面で使えます
- 注文ボタンを押してから決済完了までの間、カートをロックしたい
- API処理中に同時にカート編集・追加されるのを防ぎたい
- フロント側で「カートは現在処理中です」と案内したい
Cacheを使ったロックの考え方
LaravelのCache
は、一時的なデータや状態管理に便利です。
今回はCache::add()
を使って、「処理中なら他の操作をブロックする」しくみを作ります。
処理の流れ
- カート処理開始 → ロックキーを
Cache::add()
で作成 - 処理中は他のリクエストが同じキーを使って処理できない
- 処理完了時にロック解除(
Cache::forget()
)
実装例:APIでカート処理を行う
public function processCart(Request $request)
{
$userId = auth()->id();
$lockKey = 'cart:lock:user:' . $userId;
// 30秒間のロック(すでに処理中なら中断)
if (!Cache::add($lockKey, true, 30)) {
abort(423, 'Your cart is currently being processed. Please try again shortly.');
}
try {
// 実際の処理(注文、計算など)
$this->finalizeCart($userId);
} finally {
// 終了時にロック解除
Cache::forget($lockKey);
}
return response()->json(['message' => 'Cart processed successfully']);
}
カート表示・アイテムの追加の処理でもチェック
表示処理
$lockKey = 'cart:lock:user:' . auth()->id();
$isLocked = Cache::has($lockKey);
return view('cart.index', [
'cartItems' => $cartItems,
'readOnly' => $isLocked,
]);
アイテム追加処理
$lockKey = 'cart:lock:user:' . auth()->id();
if (Cache::has($lockKey)) {
abort(423, 'Your cart is currently being processed.');
}
// カートへの追加処理
Laravelありがとう:abort(423)
でロック中を表示
操作中のカートにアクセスされた場合、次のようにabort(423)でブロックできます。
if (Cache::has('cart:lock:user:' . auth()->id())) {
abort(423, 'Your cart is currently being processed.');
}
このコードで、カートが処理中ならHTTP 423 Locked
ステータスでエラーページを表示します。
カスタムエラーページも
resources/views/errors/423.blade.php
を作っておくと、見た目も整えられます!
@extends('layouts.app')
@section('title', 'カート処理中です')
@section('content')
<div class="container text-center">
<h1>⏳ カートは現在処理中です</h1>
<p>ただいまご注文の処理を行っています。しばらくしてからもう一度お試しください。</p>
<a href="{{ url()->previous() }}" class="btn btn-primary">戻る</a>
</div>
@endsection
処理中に別の操作が入り込むバグは追っかけにくくて厄介です。
Laravelのキャッシュをうまく使えば、こんな風に排他制御が実現できます!
もっといい方法があるかもしれないですが、今回はこの方法を採用しました。
さらに強固なロックについてはまた勉強してみたいと思います。
読んでくださってありがとうございました。
それではまた!