In my Controller, I need to check if a session has expired, and if so, update the value:
public function some_method(Request $request)
{
$session_expiry_date = session('session_expiry_date');
if ($session_expiry_date < now()) {
$some_value = Str::random(30);
session(['some_value' => $some_value]);
} else {
$some_value = session('some_value');
}
session(['session_expiry_date' => now()]);
// proceed to update or create some record on the DB
}
The problem occurs when the session is expired, and there are quick multiple requests to the same page. Then, for those immediate requests, each request creates a new random string and updates the session.
So the last request will have the last session value, however, by that time, the database created multiple records because, for each of these requests, the session expired for a moment.
For example, a user clicks example.com/page1
twice quickly while the session was expired. Now there are 2 requests that read the session as expired, set a new key, and create 2 records with 2 different keys, even though there was supposed to be only one.
How can I prevent that without using cache, or not on the DB side (i.e. with DB locks), but rather on the code side?
2
Answers
Answer update based on your question update:
One approach is to use a flag stored in the session itself to indicate whether a request is already in the process of updating the session.
To lock the session, you can use
block
on your route. The session locking will be acquired for this request whenever many simultaneous requests are incoming.So, if this request is for say
example.com/page1
, then the snippet would be:However, for this to be in effect, you must be using a cache driver that supports atomic locks. Quoting from the docs: