Skip to content

Instantly share code, notes, and snippets.

@awwx
Last active May 4, 2024 11:19
Show Gist options
  • Save awwx/ab23234a7d3d43cf83003f3bf41937c7 to your computer and use it in GitHub Desktop.
Save awwx/ab23234a7d3d43cf83003f3bf41937c7 to your computer and use it in GitHub Desktop.
observe Missionary task and flow events
;; Newer version at https://gist.github.com/awwx/6d02e6ea702bdc499bcf847e9b9bb98f
(ns mobserve
(:require
[missionary.core :as m]))
;; Encapsulate differences between Clojure and ClojureScript
;; on how IFn and IDeref are implemented.
#?(:clj
(deftype FlowIterator [transfer cancel]
clojure.lang.IDeref
(deref [_this]
(transfer))
clojure.lang.IFn
(invoke [_this]
(cancel)))
:cljs
(deftype FlowIterator [transfer cancel]
IDeref
(-deref [_this]
(transfer))
IFn
(-invoke [_this]
(cancel))))
(defn println-reporter [description msg & args]
;; Lazy evaluation interacts badly with dynamic binding;
;; evaluate the pr-str before println changes the print mode.
(let [pr-args (mapv pr-str args)]
(apply println description msg pr-args)))
(defn observe-task
([description task]
(observe-task println-reporter description task))
([report description task]
(fn [s f]
(let [cancel! (task
(fn [v]
(report description :succeeded v)
(s v))
(fn [e]
(report description :failed e)
(f e)))]
(report description :instantiated)
(fn []
(report description :canceled)
(cancel!))))))
(defn hook-call [thunk successful-call call-threw]
(try
(let [v (thunk)]
;; This isn't quite right: we catch errors thrown by
;; `successful-call`, not just `thunk`.
(successful-call v)
v)
(catch #?(:clj Throwable, :cljs :default) e
(call-threw e)
(throw e))))
(defn observe-flow
([description flow]
(observe-flow println-reporter description flow))
([report description flow]
(fn [notifier terminator]
(let [child-iterator
(flow
(fn notify []
(report description :notified)
(notifier))
(fn terminate []
(report description :terminated)
(terminator)))]
(report description :instantiated)
(FlowIterator.
(fn transfer []
(hook-call
(fn [] @child-iterator)
(fn [v]
(report description :transferred-value v))
(fn [e]
(report description :transferred-error e))))
(fn cancel []
(report description :cancel-signaled)
(child-iterator)))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment