通过Mongrel Cluster使用Starling和Mongrel的多个实例

情况:

  • 在典型的集群设置中,我在Apache 2后面运行了5个mongrel实例。
  • 在我的一个初始化文件中,我使用Rufus::Scheduler安排了一个cron任务,它基本上发送了几封电子邮件。

问题:

  • 该任务运行5次,每个mongrel实例一次,每个收件人最终获得5封邮件(尽管我存储了每封已发送邮件的日志并在发送前检查了日志)。 是否有可能因为所有5个实例在同一时间运行任务,他们最终会在写入之前阅读电子邮件日志?

我正在寻找一种解决方案,使任务只运行一次。 我也有一个Starling守护进程启动并运行,可以使用。

公鸡 rails插件专门解决您的问题。 它使用rufus-scheduler并确保环境仅加载一次。

我现在这样做的方式:

  1. 尝试以独占锁定模式打开文件
  2. 获取锁定后,检查Starling中的消息
  3. 如果消息存在,则其他进程已安排该作业
  4. 再次将消息设置为队列并退出。
  5. 如果未找到消息,请安排作业,设置消息并退出

这是执行它的代码:

  starling = MemCache.new("#{Settings[:starling][:host]}:#{Settings[:starling][:port]}") mutex_filename = "#{RAILS_ROOT}/config/file.lock" scheduler = Rufus::Scheduler.start_new # The filelock method, taken from Ruby Cookbook # This will ensure unblocking of the files def flock(file, mode) success = file.flock(mode) if success begin yield file ensure file.flock(File::LOCK_UN) end end return success end # open_lock method, taken from Ruby Cookbook # This will create and hold the locks def open_lock(filename, openmode = "r", lockmode = nil) if openmode == 'r' || openmode == 'rb' lockmode ||= File::LOCK_SH else lockmode ||= File::LOCK_EX end value = nil # Kernerl's open method, gives IO Object, in our case, a file open(filename, openmode) do |f| flock(f, lockmode) do begin value = yield f ensure f.flock(File::LOCK_UN) # Comment this line out on Windows. end end return value end end # The actual scheduler open_lock(mutex_filename, 'r+') do |f| puts f.read digest_schedule_message = starling.get("digest_scheduler") if digest_schedule_message puts "Found digest message in Starling. Releasing lock. '#{Time.now}'" puts "Message: #{digest_schedule_message.inspect}" # Read the message and set it back, so that other processes can read it too starling.set "digest_scheduler", digest_schedule_message else # Schedule job puts "Scheduling digest emails now. '#{Time.now}'" scheduler.cron("0 9 * * *") do puts "Begin sending digests..." WeeklyDigest.new.send_digest! puts "Done sending digests." end # Add message in queue puts "Done Scheduling. Sending the message to Starling. '#{Time.now}'" starling.set "digest_scheduler", :date => Date.today end end # Sleep will ensure all instances have gone thorugh their wait-acquire lock-schedule(or not) cycle # This will ensure that on next reboot, starling won't have any stale messages puts "Waiting to clear digest messages from Starling." sleep(20) puts "All digest messages cleared, proceeding with boot." starling.get("digest_scheduler") 

为什么不使用mod_passenger(phusion)? 我从杂种变成了幻觉,它完美无缺(时间长度<5分钟)!