I have a synchronization problem that I am not sure how to solve in
Ruby/Rails. I have a mental model of what I need to do and how it should
work, but can’t find the way to do it in Ruby/Rails. (I’ve learned all
about Mutexes and transactions and lock! but despite my research, am
stuck). I come from the kernel programming world, so I may be framing
Here’s the deal -
- I have a database object, call it a Meter. Meters have all sorts of
- My users can do things to meters and their associated objects via
standard web requests.
- I have a cron taks that runs on the server (Heroku) periodically and
also does things to meters and their associated objects.
- If a user is mucking about with a specific meter or it’s associated
objects at the same time as the cron task is trying to muck with the
meter or associated objects, then there’s potential for a data
So - I need to block the cron task from mucking about with a Meter and
its associated objects while a user is doing so (and vice versa).
In my old kernel world, I would have defined a lock on each meter.
I want to assure that a section of code that mucks with a meter is not
running concurrently with another section of code that mucks with the
meter, I would wrap each code section that mucks with meters in a
Lock/Unlock pair as follows:
m = get_my_meter
do section 1 stuff to meter and associated objects
m = get_my_meter
do section 2 stuff to meter and associated objects
The resulting behavior is that (assuming that two code sections tried to
operate on the same meter concurrently), one would get there first and
second would be blocked until the first called the OSUnlock. At that
the second would run and I would be assured that the code sections would
always run in sequence for any given meter (as opposed to concurrently).
In Ruby/Rails, I see that there are mutexes, but they seem to be
to multiple threads running on the same in memory objects. In my case,
user request is going to load its copy of the meter from the database
the cron task is going to load its copy, so - mutexes don’t help.
Transactions and pessimistic locking seemed promising, but from my
experimentation with them they will only prevent concurrent operations
the specific object that is locked. Operations on associated objects,
if they are inside transaction blocks, can still run concurrently. So -
seems that the executing code is not waiting, rather, the database
for the locked object only, is waiting.
I need to block the cron task from executing any further than where the
lock is taken until the user task releases the lock (and vice versa).
do I do that?