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

abdulazeezvp's avatar

Laravel cache lock(atomic lock),looking for a solution with multiple combination of key

Hi, I am using atomic lock to prevent from processing same task before completing existing one , will help me to get expected output. I implemented cache lock as follows

step1: create a unique regeneratable key with a prefix and service ids(array : numeric, ascending order), used implode to make as a string with hyphen separated, so my lock key look like

		prefix: service:1-2-3-4-5

Step2: creating lock like explained in Laravel 8 doc

step3: block

step4: process task

step5: release lock

My problem is in step 1: where a user can make any random combination of array of service ids, for example if I choose two service task with a combination, [1,2] and [1,3].So my cache keys look like

prefix: service:1-2 and prefix: service:1-3

so in this case there is possibility for taking same service id for processing which expected to be locked by previous process of same service id. which leads to a lock ineffectiveness.

for example: if select a task list from DB like:

		for 1st combo with service ids 1,2, query will be :   

			 $query->whereIn('id', [1,2]).

		for 2nd combo with service ids 1,3, query will be : 

			 $query->whereIn('id', [1,3]).

so there is possibility for getting values of service id 1 and trying to process it by both locking keys

step4 is little long, with multiple selection queries and updating queries

:- its not possible to remove random combination of array, will affect user experience

Is there any solution to solve this problem, it will be very helpful

Thanks in advance

additional details: Laravel version 8.51.0

0 likes
3 replies
Sinnbeck's avatar

Why not just lock each id individually? And then check for all requested ids, and bail if there is a lock on any of them

abdulazeezvp's avatar

@Sinnbeck How to implement using block

like this? example() { foreach($service_ids as $service_id) {

					$key='prefix'.$serviceid;
					$lock[$serviceid] = cache()->lock($key, 10);

				}
			try{
							foreach($service_ids as $service_id){
							$lock[$serviceid]->block(10);
					}
					//process code
			}
			catch(Throwable $e){
					//release lock and return

			}
					//release lock and return
	}

Will this work?

martin-coded's avatar

I have a similar situation. It seems it workes as expected. But how can I know which one of the locks has thrown the LockTimeoutException?

When I take a look at the code and try to understand it, it seems that all the locks are getting released, also when the LockTimeoutException is thrown. This happilly doesn't happen. Does Laravel ignores the release call, when the LockTimeoutException is catched or do I miss something?

    $locks = [];

    foreach ($items as $item) {
        $locks[] = Cache::lock("some_dynamic{$item['value']}", 60);
    }

    try {
        foreach ($locks as $lock) {
            $lock->block(1);
        }
        sleep(20);

    } catch (LockTimeoutException $e) {
        abort(500);
    } finally {
        foreach ($locks as $lock) {
            $lock?->release();
        }
    }

    return new JsonResponse(['success' => 'my_data'], 201);

Please or to participate in this conversation.