Reputation: 509
I am trying to fix a problem when running multiple tests that all login and search for emails in a shared IMAP email server account. Tests use a helper that uses NET::IMAP for login/search/delete and they occasionally fail when logging in or searching for emails. I think this is because of concurrent access of the mailbox by multiple rspec test runs in parallel.
I read about the MonitorMixin in Ruby but from what I understand that is for use by threads spawned within a process rather than between processes. I found this blog post that describes using Redis::Semaphore to implement a distributed lock: https://docs.knapsackpro.com/2017/when-distributed-locks-might-be-helpful-in-ruby-on-rails-application. But that needs Redis.
The tests are for a Ruby Sinatra app with postgres, so I do have postgres to use for shared locking amongst all rspec tests. So I guess I could build a simple database semaphore, like https://udby.com/archives/14 seems to describe.
Is there a simpler way to solve this problem of multiple processes needing to access a shared resource?
Upvotes: 0
Views: 281
Reputation: 509
Thanks @konstantin-strukov. I couldn't get advisory locks to work using the with_advisory_lock Ruby gem. For whatever reason, after adding the gem to the project Gemfile, the Active Record model classes did not get extended to have the with_advisory_lock
method. I am not sure if there is anything else I need to have done for the models to get extended.
I ended up using a file lock, which is included in the Ruby 'kernel' and that worked fine. Thanks to this other Stack Overflow answer. Here is a snippet:
class EmailChecker
def initialize
@lock_file_path = '/tmp/rspec-imap-flock'
end
def check_mail
open(@lock_file_path, File::CREAT) do |f|
puts 'Acquiring file lock to access IMAP server...'
# This will block if another process/rspec using this class is
# already using this method and thus has acquired the file lock
f.flock(File::LOCK_EX)
puts 'Acquired file lock!'
# Do mail checking and processing
# The end of the block will result in the file getting closed
# and the lock getting released.
end
end
Upvotes: 1