Introducing a Reactive Lock for Scala
TL;DR: https://github.com/kifi/ReactiveLock
At Kifi we try to follow reactive patterns as much as possible. Over the last two years we’ve come to appreciate the strengths of the pattern, but also run into some weaknesses. This post and the accompanying open source library is about two particular issues we’ve found not to be well addressed by existing libraries or language features:
- Concurrency Control, i.e. limiting the concurrency of parts of the code.
There are many places where this need can come up, especially in the context of resource contention. The scenario where it is perhaps most critical for us are inter service calls in our SOA. Cheap to make, but expensive to fulfill request are a common occurrence in a SOA and, basically, we want to prevent one service from accidentally DOSing another.
Now, there are of course constructs in the language to allow you to limit concurrency, like an Actor System or a special execution context with only a few threads (and we use those too, where appropriate), but if all you want to do is “prevent more than N threads from executing this function at the same time” that seems a bit heavy. Obviously classic locks (and their brethren) make this really easy, but they have the very undesirable property of blocking threads. Particularly bad in a reactive setting where you might be quickly starving your thread pool.
We wanted a solution that is both light on syntax, like locks, without blocking threads. - Transitioning from classic thread/lock patterns. When switching from more traditional concurrency patterns to reactive programming there is really no good way to do so gradually. We wanted a way to make refactors smaller and thus more manageable. This really applies both to code and to engineers’ skill sets.
To address these issues, we have built a component that we call a reactive lock.
In its simplest form, using a ReactiveLock bears a lot of similarity to the good old synchronized construct.
Calls to foo will return immediately with a Future, however, only 2 of these Futures will ever be actually executing at the same time.
There is another construct for dealing with a scenario where you already have a Future[_] (or => Future[_]) and a few utility functions for monitoring, but that is pretty much it. You can find some more usage details and all of the source code on github.
Comments and contributions are very welcome.
We wrote this post while working on Kifi — Connecting People with Knowledge. Learn more.
Originally published at eng.kifi.com on May 19, 2015.