我正在尝试解决运行多个测试时的问题,这些测试都登录并搜索共享IMAP电子邮件服务器帐户中的电子邮件。测试使用一个助手,该助手使用NET::IMAP进行登录/搜索/删除,并且在登录或搜索电子邮件时偶尔会失败。我认为这是因为多个rspec测试并行运行对邮箱的并发访问。
我读过Ruby中的MonitorMixin,但据我所知,它是供进程内生成的线程使用的,而不是在进程之间使用的。我发现这篇博客文章描述了使用Redis:Semaphore实现分布式锁:https://docs.knapsackpro.com/2017/when-distributed-locks-might-be-helpful-in-ruby-on-rails-application.但这需要Redis。
这些测试是针对带有postgres的Ruby Sinatra应用程序的,所以我确实有postgres用于所有rspec测试之间的共享锁定。所以我想我可以构建一个简单的数据库信号量,比如https://udby.com/archives/14似乎在描述。
有没有一种更简单的方法来解决多个进程需要访问共享资源的问题?
谢谢@konstantin strukov。我无法使用with_advisory_lock Ruby gem使咨询锁工作。无论出于何种原因,在将gem添加到项目Gemfile之后,Active Record模型类没有扩展为具有with_advisory_lock
方法。我不确定我是否还需要做些什么来扩展模型。
我最终使用了一个文件锁,它包含在Ruby的"内核"中,运行良好。多亏了另一个Stack Overflow答案。以下是一个片段:
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