Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure/Jetty:强制URL一次只命中一次_Clojure_Locking_Jetty - Fatal编程技术网

Clojure/Jetty:强制URL一次只命中一次

Clojure/Jetty:强制URL一次只命中一次,clojure,locking,jetty,Clojure,Locking,Jetty,我正在开发Clojure/Jetty web服务。我有一个特殊的url,我希望一次只为一个请求提供服务。如果url被请求,并且在返回之前,再次请求url,我想立即返回。因此,在我定义路线的more core.clj中,我有如下内容: (def work-in-progress (ref false)) 然后过一会儿 (compojure.core/GET "/myapp/internal/do-work" [] (if @work-in-progress "Work

我正在开发Clojure/Jetty web服务。我有一个特殊的url,我希望一次只为一个请求提供服务。如果url被请求,并且在返回之前,再次请求url,我想立即返回。因此,在我定义路线的more core.clj中,我有如下内容:

(def work-in-progress (ref false)) 
然后过一会儿

(compojure.core/GET "/myapp/internal/do-work" []
    (if @work-in-progress
        "Work in Progress please try again later"
        (do
            (dosync
                (ref-set work-in-progress true))
            (do-the-work)
            (dosync
                (ref-set rebuild-in-progress false))
            "Job completed Successfully")))
我已经在本地Jetty服务器上尝试过了,但是我似乎能够点击两次url,并且加倍了工作。在线程化web服务器环境中,在Clojure中实现这一点的好模式/方法是什么?

想象一下问题中提出的解决方案

  • 线程A开始执行处理程序的主体
    @work-in-progress
    false
    ,因此它进入
    do
    表达式。但是,在它成功地将
    正在进行的工作
    的值设置为
    之前
  • 线程B开始执行处理程序的主体
    @work-in-progress
    为false,因此它进入
    do
    表达式
  • 现在两个线程同时执行
    (执行工作)
    。这不是我们想要的

    要防止此问题,请在
    dosync
    事务中检查并设置ref的值

    (compojure.core/GET "/myapp/internal/do-work" []
      (if (dosync
            (when-not @work-in-progress
              (ref-set work-in-progress true)))
        (try
          (do-the-work)
          "Job completed Successfully"
          (finally
            (dosync
              (ref-set work-in-progress false))))
        "Work in Progress please try again later"))
    
    在这个场景中,您可能会发现另一个有用的抽象是atom和


    实际上,这是锁的自然使用情形;特别是,一个

    我在回答之前的一个问题时也出现了同样的模式;我将在这里重复相关的代码:

    (import java.util.concurrent.locks.ReentrantLock)
    
    (def lock (ReentrantLock.))
    
    (defn start []
      (if (.tryLock lock)
        (try
          (do-stuff)
          (finally (.unlock lock)))
        (do-other-stuff)))
    

    tryLock
    方法尝试获取锁,如果成功,则返回
    true
    ,否则返回
    false
    ,在这两种情况下都不阻塞。

    除了获得与锁/标志等效的功能外,还应考虑排队访问资源,队列可以让您观察资源争用以及其他优点。

    这真是太好了:我从未考虑过使用
    比较和设置
    以事务方式获取有关原子的信息,同时将其更改为其他内容。您可能需要确保在
    (执行此工作)
    引发异常的事件中释放“锁”,或者无论如何注意问题并采取措施。因此,我将用
    (尝试(完成工作)(最终(发布)))
    或类似的方法(请参阅我的答案,以获得带有实际锁的完整代码片段)替换
    (完成(完成工作)(发布))
    。非常感谢@MichałMarczyk。我已经确定了答案。
    (import java.util.concurrent.locks.ReentrantLock)
    
    (def lock (ReentrantLock.))
    
    (defn start []
      (if (.tryLock lock)
        (try
          (do-stuff)
          (finally (.unlock lock)))
        (do-other-stuff)))