Wandeln Sie diesen Clojure Anruf in eine faule Sequenz
-
06-07-2019 - |
Frage
ich mit einem Messaging-Toolkit gerade arbeitete (es passiert Verbreiten sein, aber ich weiß nicht, dass die Details ankommt). Empfangen von Nachrichten von diesem Toolkit erfordert einigen Textvorschlag:
- Erstellen Sie eine Verbindung mit dem Dämon.
- Schließen Sie sich einer Gruppe.
- Erhalten Sie eine oder mehrere Nachrichten.
- Lassen Sie die Gruppe.
- Trennen vom Dämon.
Im Anschluss an einige Idiome, die ich verwendet habe gesehen anderswo , ich war in der Lage zu kochen einige Funktionen Arbeits der Spread-Java-API und Clojure der Interop-Formulare mit:
(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)))
(Im Grunde das gleiche Idiom wie with-open
, nur, dass die SpreadConnection
Klasse verwendet disconnect
statt close
. Grr. Außerdem habe ich einige Makros weggelassen, die hier nicht relevant für die strukturelle Frage sind.)
Das funktioniert gut genug. Ich nenne kann-Nachricht empfängt, die von innen von einer Struktur wie:
(with-daemon {:host "localhost" :port 4803}
(with-group "aGroup"
(... looping ...
(let [msg (receive-message)]
...))))
Es fällt mir ein, würde das receive-message
Reiniger zu verwenden, wenn es eine unendliche faul Sequenz waren die Nachrichten produziert. Also, wenn ich aussehen sollte etwas eine Gruppe und erhalten Nachrichten, die anrufende Code beitreten wollten:
(def message-seq (messages-from {:host "localhost" :port 4803} "aGroup"))
(take 5 message-seq)
Ich habe viele Beispiele für faule Sequenzen ohne Bereinigung gesehen, das ist nicht zu hart. Der Haken ist, Schritte # 4 und 5 von oben: die Gruppe verlassen und vom Dämon trennen. Wie kann ich binde den Zustand der Verbindung und die Gruppe in die Sequenz und den notwendigen Bereinigungscode ausgeführt werden, wenn die Sequenz nicht mehr benötigt wird?
Lösung
Dieser Artikel beschreibt wie genau das zu tun, Clojure-contrib Fill-Warteschlange verwendet wird. In Bezug auf Cleanup - die nette Sache über Fill-Warteschlange ist, dass Sie eine Sperrfunktion, die selbst aufräumt liefern können, wenn ein Fehler auftritt oder ein Zustand erreicht. Sie können auch einen Verweis auf die Ressource halten, um sie extern zu steuern. Die Sequenz wird nur beenden. Also je nach semantischer Anforderung Sie die Strategie wählen, das paßt.
Andere Tipps
Versuchen Sie folgendes:
(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))))))
Set getan? true, wenn Sie die Liste zu beenden. Außerdem werden alle Ausnahmen in (.receive CNX) geworfen wird auch die Liste beenden.