Canonical Way to Ensure Only One Instance of a Service Is Running / Starting / Stopping in Clojure?

ぐ巨炮叔叔 提交于 2019-12-05 18:27:36

This is actually a natural fit for a simple lock:

(locking x
  (do-stuff))

Here x is the object on which to synchronize.

To elaborate: starting and stopping a service is a side effect; side effects should not be initiated from inside a transaction, except possibly as Agent actions. Here though locks are exactly what the design calls for. Note that there's nothing wrong in using them in Clojure when they are a good fit for the problem at hand, in fact I would say locking is the canonical solution here. (See Stuart Halloway's Lancet, introduced in Programming Clojure (1st ed.), for an example of a Clojure library using locks which has seen some widespread use, mostly in Leiningen.)

Update: Adding fail-fast behaviour:

This is still a good fit for a lock, namely a java.util.concurrent.locks.ReentrantLock (follow link for Javadoc):

(import java.util.concurrent.locks.ReentrantLock)

(def lock (ReentrantLock.))

(defn start []
  (if (.tryLock lock)
    (try
      (do-stuff)
      (finally (.unlock lock)))
    (do-other-stuff)))

(do-stuff) will be executed if lock acquisition succeeds; otherwise, (do-other-stuff) will happen. Current thread will not block in either case.

This sounds like a good use case for agents, they allow you to serialize changes to a piece of mutable state, the Clojure Agents documentation has a good overview. You can use the error handler and agent-error methods to handle exceptions and never need to worry about locks or race conditions.

(def service (agent {:status :stopped}))

(defn start-service [{:keys [status] :as curr}]
  (if (= :stopped status)
    (do 
      (println "starting service")
      {:status :started})
    (do 
      (println "service already running")
      curr)))

 ;; start the service like this
 (send-off service start-service)

 ;; gets the current status of the service
 @service
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!