2

私はメッセージング ツールキットを使用しています (たまたまスプレッドですが、詳細が重要であることはわかりません)。このツールキットからメッセージを受信するには、定型文が必要です。

  1. デーモンへの接続を作成します。
  2. グループに参加します。
  3. 1 つ以上のメッセージを受信します。
  4. グループを離れます。
  5. デーモンから切断します。

他の場所で使用されているのを見たイディオムに従って、Spread の Java API と 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)))

(基本的には と同じイディオムwith-openですが、SpreadConnectionクラスが . Grrdisconnectの代わりに使用するだけcloseです。また、ここでの構造的な問題に関係のないマクロをいくつか省略しました。)

これは十分に機能します。次のような構造体の内部から receive-message を呼び出すことができます。

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

receive-messageメッセージを生成する無限の遅延シーケンスである場合、使用するのがよりクリーンになると思います。したがって、グループに参加してメッセージを受け取りたい場合、呼び出しコードは次のようになります。

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

クリーンアップのない遅延シーケンスの例をたくさん見てきましたが、それほど難しくありません。問題は、上記のステップ 4 と 5 です。グループを離れ、デーモンから切断します。接続とグループの状態をシーケンスにバインドし、シーケンスが不要になったときに必要なクリーンアップ コード実行するにはどうすればよいですか?

4

2 に答える 2

6

この記事では、clojure-contrib fill-queue を使用して正確にそれを行う方法について説明します。クリーンアップについて - fill-queue の優れた点は、エラーが発生した場合や何らかの条件に達した場合に、それ自体をクリーンアップするブロッキング関数を提供できることです。リソースへの参照を保持して、外部から制御することもできます。シーケンスはすぐに終了します。したがって、セマンティック要件に応じて、適切な戦略を選択する必要があります。

于 2009-10-27T02:48:05.360 に答える
3

これを試して:

(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))))))

セット完了?リストを終了する場合は true にします。また、(.receive cnx) で例外がスローされると、リストも終了します。

于 2009-10-28T13:48:19.113 に答える