2012-10-02 5 views
0

Je suis en train de réaliser quelque chose comme ça dans MonogDB:Blocage findAndModify en Ruby MongoDB pilote

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 

assez Je veux naturellement une file d'attente de disque soutenu par Ruby qui ne détruit pas ma mémoire disponible, je Si je l'utilise avec le framework Anemone Web Spider qui utilise par défaut la classe Queue, il y a une fourchette qui peut utiliser la classe SizedQueue, mais en utilisant un SizedQueue pour la "queue de page" et la "file d'attente de liens", il est souvent deadlocks, vraisemblablement parce qu'il essaie de défaire une page et de la traiter, et il a trouvé de nouveaux liens, et cette situation ne peut pas être réconciliée.

Il y a aussi une implémentation existante d'une file d'attente Redis, mais qui épuise aussi toute ma mémoire disponible sur cette machine (mémoire disponible est de 16 Go, il est donc pas trivial)

En raison de ce que je veux utiliser ce backend MongoDB , mais je pense que la mise en œuvre est folle. Le Thread.pass ressemble à une solution horrible, mais Anemone est multi-thread, et MongoDB ne supporte pas les lectures bloquantes, donc c'est une situation délicate.

Voilà mes références:

Questions:

  • Quelqu'un peut-il commenter sur la façon saine d'esprit est ce, par rapport à sleep (qui devrait déclencher la machine virtuelle pour passer le contrôle au fil suivant, de toute façon, mais sleep se sent plus sale)
  • Dois-je peut-être Thread.pass et sleep? (Je suppose que non, voir ci-dessus)
  • Puis-je faire lire le bloc MongoDB? On en a parlé ici, mais cela n'est jamais arrivé à rien: https://groups.google.com/forum/?fromgroups=#!topic/mongodb-user/rqnHNFXaZ0w
+0

Qu'est-ce qui vous fait penser que MongoDB ne supporte pas les lectures bloquantes? Si vous faites un find_one() ou un find_and_modify(), l'opération ne retournera pas tant que la requête n'est pas terminée et que le résultat est de retour sur le client. Vous aurez besoin de faire des écritures "Safe Mode" afin d'avoir des écritures bloquantes. –

+0

William, comment pourrait-on changer le code ci-dessus pour être une lecture bloquante?(Je définis le blocage comme ne retournant pas jusqu'à ce qu'un résultat satisfasse la requête) –

+0

simplement faire >> jusqu'à _r = collection.find_and_modify ({sort: {_id: Mongo :: ASCENDING}, enlever: vrai}) << devrait bloquer - juste dans ce fil, bien sûr –

Répondre

0

1) Les lectures dans MongoDB sont bloquantes. Si vous faites un findOne() ou un findAndModify(), l'appel ne retournera pas jusqu'à ce que les données soient présentes du côté client. Si vous faites un find(), l'appel ne retournera pas tant que vous n'aurez pas de curseur: vous pourrez alors parcourir le curseur autant que nécessaire.

2) Par défaut, les écritures sur MongoDB sont "fire and forget". Si vous vous souciez de l'intégrité des données, vous devez effectuer des écritures sécurisées en définissant: safe => true dans votre connexion, base de données ou objet de collection

0

Kernel.sleep est en fait une meilleure solution, car sinon vous y retournerez (mais en passant le contrôle à d'autres threads après chaque requête). Comme findAndModify est atomique, un seul thread (même sur JRuby) prendra le travail, donc je ne comprends pas très bien le problème de "blocage" ici.

+0

Je ne veux pas dormir, du tout - je veux "arrêter" et attendre que cette requête retourne un document, s'il n'y a pas de documents, je veux arrêter le fil ici et assurez-vous qu'il ne retourne pas jusqu'à ce qu'il est une. Je veux éviter de dormir, car le temps le plus court que l'on puisse dormir est de 0,1s en Ruby (de manière fiable). C'est une perte de temps inutile. Je veux que Mongo ne revienne pas de cet appel jusqu'à ce qu'un document corresponde à cette requête. –