laravel / ideas

Issues board used for Laravel internals discussions.
938 stars 31 forks source link

Shared Lock/Counting Semaphore #2620

Closed Spice-King closed 3 years ago

Spice-King commented 3 years ago

I've bumped into needing such a thing due to third party API limitations. shakes fist at Microsoft

Laravel's lock (binary semaphores) API provides quite a nice developer experience, so I wanted to suggest a similar API.

$sharedLock = Cache::sharedLock('semaphore', seconds: 20, count: 5)

The shared lock object should be almost the same in API functionality, with the only clear surface additions being getting the active number of locks held or acquiring multiple shares of a lock (like $lock->get(2) to grab 2 shares, though, I'd just argue to take multiple individual lock objects for as rare as I think one would need to).

Given enough free time, I might write up a PR for this if there is enough interest, but I know I'm rather swamped at the moment. I personally would only care about the Redis cache adapter, but such a PR would need to add it for all of them.

themsaid commented 3 years ago

Can you explain the use case more?

Spice-King commented 3 years ago

We deal with Microsoft's Graph API, which has some rather low limits for concurrent requests, 4 or 5 in some cases. It's probably not going to be the only thing as I start to tie in other things.

https://docs.microsoft.com/en-us/graph/throttling

I'm rather sure that there are other services that can have low enough limits that between servicing front end requests and processing several other wise unrelated jobs in back end queues, or bill based on some metric tied to concurrent requests or temporally occupied resources.

It's may not a solution for everything, but for what I'd need, blocking for a up to a few seconds for something that takes 1/5th of a second to do is better than having the front end getting a 500 for a thrown exception, jobs to fail on a choke point, or get yelled at by my boss for tying up too much stuff.

A use for it inside Laravel would be including a queue middleware that limits on concurrency rather than a rate limit, as an more generic example.

themsaid commented 3 years ago

You can use Redis::funnel() to use a concurrency limiter.