Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

NabeelHassan's avatar

Laravel Cache::lock($lockName)->release() always return false

Hi I am using cache locks in laravel 8, I acquire lock for 5 seconds but my task end before then 5 second so when i try to release lock before 5 seconds it always return false and not releasing lock as well, also i tried Cache::lock($lockName)->forceRelease() which is releasing lock , so i want to know why i am unable to release lock with Cache::lock($lockName)->release() . And one more thing to add i am able to release lock with Cache::lock($lockName)->release() in my another project which is build on laravel 5.7, my cache driver is redis, this is my code example

public function available_providers_v1(Request $request)
    {
        try {
            $latitude = $request->s_latitude;
            $longitude = $request->s_longitude;
            $service_type = $request->service_type;

            $lockName = config('cache.prefix') . '_filter_available_providers_v1_lock';
            $lock = Cache::lock($lockName, 5)->block(3);
            $distance = Setting::get('provider_search_radius', '10');
            $occupiedProviders = Redis::smembers('occupied_providers');
            $Providers = Provider::doesnthave('incoming_requests')
                ->whereNotIn('id', $occupiedProviders)
                ->with('service')
                ->select(DB::Raw("(6371 * acos( cos( radians('$latitude') ) * cos( radians(latitude) ) * cos( radians(longitude) - radians('$longitude') ) + sin( radians('$latitude') ) * sin( radians(latitude) ) ) ) AS distance"), 'id')
                ->where('status', 'approved')
                ->whereRaw("(6371 * acos( cos( radians('$latitude') ) * cos( radians(latitude) ) * cos( radians(longitude) - radians('$longitude') ) + sin( radians('$latitude') ) * sin( radians(latitude) ) ) ) <= $distance")
                ->whereHas('service', function ($query) use ($service_type) {
                    $query->where('status', 'active');
                    $query->where('service_type_id', $service_type);
                })
                ->orderBy('distance', 'asc')
                ->get();
            // if (count($Providers) > 0) {
            //     Redis::sadd('occupied_providers', $Providers[0]->id);
            // }
            return ['data' => ['providers' => $Providers], 'status' => 200, 'success' => ['message' => 'Available Providers List', 'code' => "available_providers_list"]];
        } catch (Exception $e) {
            Log::info($e);
            return ['data' => null, 'status' => 500, 'error' => ['message' => trans('api.something_went_wrong'), 'code' => "server_error"]];
        } catch (LockTimeoutException $e) {
            Log::info('LockTimeoutException for ' . $lockName . 'in available providers list v1');
            return ['data' => null, 'status' => 500, 'error' => ['message' => 'Sorry we unable to process this request at the moment, please try again', 'code' => 'lock_timeout_exception_unable_to_process_request']];
        } finally {
            if ($lock) {
                // Cache::lock($lockName)->release();
                // Cache::lock($lockName)->release();
                return response()->json(Cache::lock($lockName)->release());
                return response()->json(Cache::lock($lockName)->forceRelease());
            }
        }
    }
0 likes
9 replies
Snapey's avatar

finally will not run if you return in the middle of try catch ?

Edit: I looked it up

One notable interaction is between the finally block and a return statement. If a return statement is encountered inside either the try or the catch blocks, the finally block will still be executed. Moreover, the return statement is evaluated when encountered, but the result will be returned after the finally block is executed. Additionally, if the finally block also contains a return statement, the value from the finally block is returned.

So if you are getting data out of the function then if ($lock) must be false, skipping your release statement

1 like
NabeelHassan's avatar

@snapey i think finally will run whatsoever, an it is running in my case as well, and to clear my point i just added return response()->json(); in finally to check the response of Cache::lock($lockName)->release(), otherwise i am not returning anything from finally block

Snapey's avatar

You don't seem to be using cache lock correctly? no $lock->get() ?

looking at your code, why do you even lock? You are not updating anything where a race condition might be an issue

NabeelHassan's avatar

@snapey i am acquiring lock with $lock = Cache::lock($lockName, 5)->block(3); and it is successfully acquiring lock as well, and i am using lock in this function because i don't want to execute this function logic by two process simultaneity, i am searching nearest driver in this function an i don't want to assign same driver to two separate request

Snapey's avatar

@NabeelHassan the problem with your code is that when you acquire the driver, until such time as you allocate that driver, another process can follow fractionally behind and grab the same driver.

to be of any use you would need to find the driver AND add them to the occupied provider's collection (I assume) within the same atomic lock.

But examine your code. it is not behaving the way you expect.

1 like
NabeelHassan's avatar

@snapey i already handled what you are saying, I am pushing driver into redis set the line is commented in code for test purpose

 // if (count($Providers) > 0) {
            //     Redis::sadd('occupied_providers', $Providers[0]->id);
            // }
Snapey's avatar

@NabeelHassan I see now.

You can simplify this code like

    $provider = Provider::doesnthave('incoming_requests')
                ->whereNotIn('id', $occupiedProviders)
                ->with('service')
                ->select(DB::Raw("(6371 * acos( cos( radians('$latitude') ) * cos( radians(latitude) ) * cos( radians(longitude) - radians('$longitude') ) + sin( radians('$latitude') ) * sin( radians(latitude) ) ) ) AS distance"), 'id')
                ->where('status', 'approved')
                ->whereRaw("(6371 * acos( cos( radians('$latitude') ) * cos( radians(latitude) ) * cos( radians(longitude) - radians('$longitude') ) + sin( radians('$latitude') ) * sin( radians(latitude) ) ) ) <= $distance")
                ->whereHas('service', function ($query) use ($service_type) {
                    $query->where('status', 'active');
                    $query->where('service_type_id', $service_type);
                })
                ->orderBy('distance', 'asc')
                ->first();
    if ($provider) {
        Redis::sadd('occupied_providers', $provider->id);
    }

notes

  • use first instead of get()
  • use singular $provider now that it is a first() method
  • use camel case for variable names (eg $provider not $Provider)

Also, you need to handle the case of no results.

Then, in your finally block

        } finally {
            if ($lock) {
                // Cache::lock($lockName)->release();
                // Cache::lock($lockName)->release();
                return response()->json(Cache::lock($lockName)->release());
                return response()->json(Cache::lock($lockName)->forceRelease());
            }
        }

According to the php documentation I posted first, Your should not return ANYTHING in the finally section, since;

Additionally, if the finally block also contains a return statement, the value from the finally block is returned.

So you will not get any output from your function other than the result of cache lock release.

Please or to participate in this conversation.