Pergunta

Eu estou trabalhando com um conjunto de ferramentas de mensagens (que passa a ser Espalhe mas eu não sei que os detalhes são importantes). Recebendo mensagens deste kit de ferramentas requer algum clichê:

  1. Criar uma conexão com o daemon.
  2. Participe de um grupo.
  3. Receber uma ou mais mensagens.
  4. Deixe o grupo.
  5. Desconectar do daemon.

Na sequência de algumas expressões idiomáticas que eu vi usado outro lugar , eu era capaz de cozinhar algumas funções de trabalho que utilizam API Java de propagação e as formas de interoperabilidade do 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)))

(Basicamente o mesmo idioma como with-open, só que os usos de classe SpreadConnection disconnect vez de close. Grr. Além disso, eu deixei de fora algumas macros que não são relevantes para a questão estrutural aqui.)

Isso funciona bem o suficiente. Eu posso chamar receber-mensagem de dentro de uma estrutura como:

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

Ocorre-me que receive-message seria mais limpo para uso se fosse uma seqüência preguiçoso infinito que produz mensagens. Então, se eu queria participar de um grupo e receber mensagens, o código de chamada deve ser algo como:

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

Eu vi muitos exemplos de seqüências preguiçosos, sem limpeza, que não é muito difícil. O prendedor é passos # 4 e 5 a partir de cima: deixando o grupo e desligar do daemon. Como posso vincular o estado da conexão e grupo na seqüência e executar o código de limpeza necessária quando a seqüência não é mais necessária?

Foi útil?

Solução

Este artigo descreve como fazer exatamente isso usando clojure-contrib fill-fila. Em relação à limpeza - a coisa pura sobre fill-fila é que você pode fornecer uma função de bloqueio que se limpa-se se houver um erro ou alguma condição alcançada. Você também pode manter uma referência para o recurso para controlá-lo externamente. A sequência será apenas terminar. Então, dependendo de sua exigência semântica você terá que escolher a estratégia que se encaixa.

Outras dicas

Tente isto:

(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 feito? a verdade quando você quer terminar a lista. Além disso, quaisquer exceções lançadas em (CNX .receive) também irá terminar a lista.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top