Question

Je travaille avec une boîte à outils de messagerie (elle se trouve être Diffuser , mais je ne le sais pas. les détails comptent). La réception des messages de cette boîte à outils nécessite un passe-partout:

  1. Créez une connexion au démon.
  2. Rejoindre un groupe.
  3. Recevez un ou plusieurs messages.
  4. Quittez le groupe.
  5. Déconnectez-vous du démon.

Suite à certains idiomes que j’ai vus utilisés, ailleurs , j'ai pu cuisiner certaines fonctions utilisant l'API Java de Spread et les formulaires d'interopérabilité de Clojure:

(defn connect-to-daemon
  "Open a connection"
  [daemon-spec]
  (let [connection (SpreadConnection.)
        {:keys [host port user]} daemon-spec]
    (doto connection
      (.connect (InetAddress/getByName host) port user false false))))

(defn join-group
  "Join a group on a connection"
  [cxn group-name]
  (doto (SpreadGroup.)
    (.join cxn group-name)))

(defn with-daemon*
  "Execute a function with a connection to the specified daemon"
  [daemon-spec func]
  (let [daemon (merge *spread-daemon* daemon-spec)
        cxn (connect-to-daemon daemon-spec)]
    (try
     (binding [*spread-daemon* (assoc daemon :connection cxn)]
       (func))
     (finally
      (.disconnect cxn)))))

(defn with-group*
  "Execute a function while joined to a group"
  [group-name func]
  (let [cxn (:connection *spread-daemon*)
        grp (join-group cxn group-name)]
    (try
     (binding [*spread-group* grp]
       (func))
     (finally
      (.leave grp)))))

(defn receive-message
  "Receive a single message. If none are available, this will block indefinitely."
  []
  (let [cxn (:connection *spread-daemon*)]
    (.receive cxn)))

(Fondamentalement identique au with-open , la classe SpreadConnection utilise disconnect au lieu de close . Grr. En outre, j'ai laissé de côté des macros qui ne sont pas pertinentes ici.)

Cela fonctionne assez bien. Je peux appeler receive-message depuis une structure telle que:

(with-daemon {:host "localhost" :port 4803}
  (with-group "aGroup"
    (... looping ...
      (let [msg (receive-message)] 
        ...))))

Il me semble que receive-message serait plus simple à utiliser s'il s'agissait d'une séquence infinie paresseuse produisant des messages. Donc, si je voulais rejoindre un groupe et recevoir des messages, le code d'appel devrait ressembler à:

(def message-seq (messages-from {:host "localhost" :port 4803} "aGroup"))
(take 5 message-seq)

J'ai vu plein d'exemples de séquences paresseuses sans nettoyage, ce n'est pas trop difficile. La capture est les étapes 4 et 5 d’en haut: quitter le groupe et se déconnecter du démon. Comment puis-je lier l’état de la connexion et du groupe à la séquence et exécuter le code de nettoyage nécessaire lorsque la séquence n’est plus nécessaire?

Était-ce utile?

La solution

Cet article décrit comment faire exactement cela en utilisant clojure-contrib fill-queue. En ce qui concerne le nettoyage, l’intéressant aspect de Fill-Queue est que vous pouvez fournir une fonction de blocage qui se nettoie si une erreur ou une condition est remplie. Vous pouvez également conserver une référence à la ressource pour la contrôler en externe. La séquence va juste se terminer. En fonction de vos besoins sémantiques, vous devrez donc choisir la stratégie qui vous convient.

Autres conseils

Essayez ceci:

(ns your-namespace
  (:use clojure.contrib.seq-utils))

(defn messages-from [daemon-spec group-name]
  (let [cnx (connect-to-deamon daemon-spec))
        group (connect-to-group cnx group-name)]
    (fill-queue (fn [fill]
                  (if done? 
                      (do
                        (.leave group)
                        (.disconnect cnx)
                        (throw (RuntimeException. "Finished messages"))
                      (fill (.receive cnx))))))

Ensemble terminé? à true lorsque vous souhaitez terminer la liste. De même, toute exception déclenchée (.receive cnx) mettra également fin à la liste.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top