Skip to content

Instantly share code, notes, and snippets.

@maxp
Last active March 3, 2019 08:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxp/c07f040bc77bda383075efe233115ed7 to your computer and use it in GitHub Desktop.
Save maxp/c07f040bc77bda383075efe233115ed7 to your computer and use it in GitHub Desktop.
threaded init/step/cleanup lifecycle
;;
;; mlib: run proccessing loop in separate thread
;;
(ns mlib.thread
(:require
[clojure.core.async :refer [thread <!!]]))
;
(defn- thread-loop [state' init step cleanup]
(try
(init state')
(loop []
(step state')
(if (::loop-flag @state')
(recur)
(cleanup @state' nil)))
(catch Exception ex
(cleanup @state' ex))))
;
(defn start-loop
" start loop in separate thread using state returned by init-fn,
exit loop on empty new-state or on exception in step-fn or cleared loop-flag
init-fn: setup state' atom in context of the new thread
step-fn: do work using state' atom
cleanup-fn: get final state and optional exception, free resources bound to the state
"
[init step cleanup]
;;
(assert fn? init)
(assert fn? step)
(assert fn? cleanup)
;
(let [state' (atom {::loop-flag true})]
{ :state state'
:thread (thread
(thread-loop state' init step cleanup))}))
;
(defn clear-loop-flag [state']
(swap! state' assoc ::loop-flag false))
;
(defn stop-loop
"reset loop-flag and wait for the thread"
[thread-state]
(when thread-state
(clear-loop-flag (:state thread-state))
(<!! (:thread thread-state))))
;
(comment
;; example
(defn init [state']
(update state' assoc :conn (make-connection cfg)))
;
(defn step [state']
(println
(read (:conn @state'))))
;
(defn cleanup [state ex]
(when ex
(error ex))
(when-let [conn (:conn state)]
(close conn)))
;
(defstate service
:start
(start-loop init step cleanup)
:stop
(stop-loop service))
;
.)
;;.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment