2017-05-13 5 views
1

Ich verwende agents, um eine Verarbeitungskette einzurichten. Ich möchte auch, dass ein Logger weiß, was passiert ist. Der gesamte Code ist hier.Einen Clojure Agent protokollieren

Ich kann sehen, dass die :charlie msg verarbeitet und geht sogar auf die log Funktion, wie es gedruckt wird ... nach wird „gesendet“ „conj'ed“ an den Logger-Agent zu sein.

Warum erscheint Charlie nie in meinem @logger?

(def logger (agent [])) ;; logger to keep track of what's done 

(defn log [msg] 
    (send logger conj msg) ;; charlie's msg is NOT conj'ed 
    (println "logged" msg)) ;; but charilies msg IS printed 

(defn create-relay [coll] 
    (reduce (comp agent vector) nil (reverse coll))) ;; see partial answer below 

(defn relay-msg [next-agent prev-msg] 
    (if (nil? next-agent) 
    (log "finished relay") 
    (let [new-msg (str prev-msg (second next-agent))] 
     ;; do something interesting with new-msg then: 
     (log new-msg) 
     ;; go do the next thing 
     (send (first next-agent) relay-msg new-msg)))) 

(send (create-relay [:alice :bob :charlie]) relay-msg "hello") 
(. java.lang.Thread sleep 5000) 
(prn @logger) 

Ausgang:

logged hello:alice 
logged hello:alice:bob 
logged hello:alice:bob:charlie 
["hello:alice" "hello:alice:bob"] 
;; expected last line to be: 
;; ["hello:alice" "hello:alice:bob" "hello:alice:bob:charlie"] 

Teil Antwort Ich habe herausgefunden, wie es funktioniert, aber ich bin noch auf der Suche nach „akzeptieren“ eine Antwort, die erklärt, wo der Fehler ging von verstecken mich.

Der Druck ist ein Nebeneffekt. Der Agent ist "konsistent" (was immer das bedeutet). Nach „Protokollierung“ charlie, ruft die nächste Zeile in dieser Zeile „zu null senden“:

(send (first next-agent) relay-msg new-msg) ;; =>(first next-agent) is nil 

Scheint, wie es ein NullPointerException sein sollte, aber es zeigt nie auf. Geschluckt, weil es in einem anderen Thread ist ???

(reduce (comp agent vector) nil (reverse coll)) 
;; => change to => 
(reduce (comp agent vector) (agent nil) (reverse coll)) 

Warum schweigt zu dem Fehler:

mit folgenden schwer zu grok Änderung festgelegt? Und ist es richtig, dass die @logging zurückgerollt wurde?
Was wäre, wenn nach dem Rollback andere Objekte "verbunden" wären mit logging?

Ich habe "Arbeits" -Code, aber ich bin immer noch auf richtiges Verhalten hier verloren. "Un" -Loggen hört sich beängstigend an.

Antwort

2

Die Antwort kann auf die Clojure reference page for Agents finden:

  1. während der Funktionsausführung Wenn andere Sendungen gemacht werden (direkt oder indirekt), werden sie erst nach stattfinden Der Status des Agenten wurde geändert.

"Andere Depeschen" bedeutet hier im Wesentlichen vor, ruft send. Wenn also relay-msg für einen bestimmten Agenten ausgeführt wird, werden alle Aufrufe an send in die Warteschlange gestellt, bis relay-msg den neuen Status des Agenten zurückgibt. Im Fall von :alice und :bob werden die in der Warteschlange befindlichen send s dann ausgelöst, sobald der Status des Agenten aktualisiert wurde.

Aber da relay-msg auf :charlie ein NullPointerException wirft, wird das Mittel für :charlie in einen Fehlerzustand versetzt und die Warteschlange send s (einschließlich der in dem Aufruf von log) werden verworfen.

Scheint wie es eine NullPointerException sein sollte, aber es erscheint nie. Geschluckt, weil es in einem anderen Thread ist ???

Sortieren von. In Wirklichkeit werden Ausnahmen durch den Agent-Dispatch-Mechanismus eingekapselt. Wenn die an send übergebene Funktion eine Ausnahme auslöst, wird sie abgefangen und der Agent wird in einen Fehlerzustand versetzt. Die Ausnahme ist auf dem Agenten gespeichert und kann über agent-error erreicht werden. (Auch nachfolgende Aufrufe an send auf einem fehlgeschlagenen Agenten werfen die ursprüngliche Ausnahme.)