在Ruby MongoDB驱动程序中阻止findAndModify

时间:2012-10-02 22:20:25

标签: ruby mongodb queue mongoid

我正试图在MonogDB中实现这样的目标:

require 'base64'
require 'mongo'

class MongoDBQueue

  def enq(thing)
    collection.insert({ payload: Base64.encode64(Marshal.dump(thing))})
  end
  alias :<< :enq

  def deq
    until _r = collection.find_and_modify({ sort: {_id: Mongo::ASCENDING}, remove: true})
      Thread.pass
    end
    return Marshal.load(Base64.decode64(_r["payload"]))
  end
  alias :pop :deq

  private

    def collection
      # database, collection & mongodb index semantics here
    end

end

当然,我想在Ruby中使用磁盘支持的队列,不会破坏我的可用内存,我使用的是Anemone web spider框架,它默认使用Queue类,有一个fork可以使用SizedQueue类,但是当对“页面队列”和“链接队列”使用SizedQueue时,它通常会死锁,大概是因为它试图将页面出列并处理它,它是找到了新的链接,这种情况无法调和。

还有一个Redis队列的现有实现,但是这也耗尽了这台机器上所有可用的内存(可用内存为16Gb,所以它并非无足轻重)

因为我想使用这个MongoDB后端,但我认为实现是疯了。 Thread.pass感觉像是一个可怕的解决方案,但Anemone是多线程的,MongoDB不支持阻塞读取,所以这是一个棘手的情况。

这是我的参考资料:

问题:

  • sleep(无论如何应该触发VM将控制传递给下一个线程,但sleep感觉更脏)相比,任何人都可以评论这是多么合理。
  • 我应该Thread.passsleep吗? (我猜不是,见上文)
  • 我可以从MongoDB块中读取吗?这里有人谈论过这个问题,但从未发生过任何事情:https://groups.google.com/forum/?fromgroups=#!topic/mongodb-user/rqnHNFXaZ0w

2 个答案:

答案 0 :(得分:0)

1)MongoDB中的读取是阻塞的。如果执行findOne()或findAndModify(),则在客户端存在数据之前,调用将不会返回。如果执行find(),则在获得游标之前调用将不会返回:您可以根据需要迭代游标。

2)默认情况下,对MongoDB的写入是&#34; fire and forget&#34;。如果您关心数据完整性,则需要通过设置安全写入:safe =&gt;在连接,数据库或集合对象中为true

答案 1 :(得分:0)

Kernel.sleep实际上是一个更好的解决方案,否则你将在那里旋转(尽管在每次查询后将控制传递给其他线程)。 由于findAndModify是原子的,只有一个线程(即使在JRuby上)也会接受这个工作,所以我不太明白这里的“阻塞”问题是什么。