2013-02-03 53 views
7

में वेब सेवा के लिए असीमित नौकरी कतार इस समय मैं एक विश्वसनीय सेवा के साथ एक वेब सेवा बनाने की कोशिश कर रहा हूं जो कुछ लंबे समय तक चलने वाले कार्यों (नौकरियों) को संभालता है।क्लोजर

विचार यह है कि उपयोगकर्ता एक पोस्ट करके नौकरी सबमिट करता है जो नौकरी की स्थिति की जांच के लिए कुछ यूआरएल देता है जिसमें परिणामों के लिए यूआरएल भी होता है। एक बार नौकरी पूरी हो जाने के बाद (यानी कुछ मूल्य डेटाबेस में लिखा गया था) परिणाम यूआरएल उचित जानकारी (परिणाम के बजाए) वापस कर देगा और नौकरी यूआरएल एक पूर्ण स्थिति का संकेत देगा।

दुर्भाग्य से गणना काफी गहन है इसलिए केवल एक ही समय में चलाया जा सकता है, इसलिए नौकरियों को कतारबद्ध करने की आवश्यकता है।

कुछ

छद्म में इस तरह

(def job-queue (atom queue)) ;; some queue 
(def jobs (atom {})) 

(defn schedule-job [params] 
    ;; schedules the job into the queue and 
    ;; adds the job to a jobs map for checking status via GET 
    ;; note that the job should not be evaluated until popped from the queue 
) 

(POST "/analyze" [{params :params}] 
(schedulde-job params)) 

(GET "job/:id" [:d] 
(get @jobs id)) 

;; Some function that pops the next item from the queue 
;; and evaluates it when the previous item is complete 
;; Note: should not terminate when queue is empty! 

मैं Lamina जो अतुल्यकालिक प्रसंस्करण की अनुमति देता है देखा है की जरूरत होगी लेकिन यह मेरी आवश्यकताओं के अनुरूप नहीं मालूम था।

मेरा प्रश्न यह है कि कतार खाली होने के बाद नौकरियों के कतार को हटाने और अपने कार्य को निष्पादित करने के बाद, कतार खाली होने पर समाप्त होने के बिना यानी आने वाली नौकरियों को लगातार संसाधित करने के बिना।

+0

मैं क्लोजर में बहुत अच्छा नहीं हूं, इसलिए कोई मदद नहीं, बस एक साइड-नोट: 204 क्यों लौटाएं? मुझे लगता है कि एक वास्तविक संदेश (केवल एक 200) को एक शरीर के साथ वापस करना बेहतर होगा कि यह अभी तक नहीं किया गया है या ऐसा कुछ है? – Nanne

+0

आप सही हैं, जो वास्तव में बेहतर हो सकता है क्योंकि "अगर क्लाइंट उपयोगकर्ता एजेंट है, तो उसे HTTP दस्तावेज़ में अनुरोध भेजने के कारण से अपना दस्तावेज़ दृश्य नहीं बदलना चाहिए, अन्यथा" कोई सामग्री नहीं "मुझे लगता है कि अधिक उपयुक्त होगा। – JoelKuiper

+0

मुझे हमेशा पसंद है अगर आरईएसटी एपीआई http पर खेलने की कोशिश नहीं करता है। जैसा कि, अगर मैं कुछ डेटा का अनुरोध करता हूं (उदाहरण के लिए किसी का खाता लेकिन गलत आईडी के साथ), मैं शरीर के अंदर 200 प्राप्त करने का अधिक प्रशंसक हूं, उदाहरण के लिए 404 उदाहरण के बजाय ऐसा कोई व्यक्ति नहीं है। वही। लेकिन यह ऑफटॉप है, इसके लिए खेद है;) – Nanne

उत्तर

9

एक java.util.concurrent.ExecutorService हो सकता है कि तुम क्या चाहते हैं। यह आपको बाद में निष्पादन के लिए नौकरी जमा करने की अनुमति देता है, और एक भविष्य देता है जिसे आप यह पूछने के लिए क्वेरी कर सकते हैं कि यह पूरा हो गया है या नहीं।

(import '[java.util.concurrent Callable Executors]) 

(def job-executor 
    (Executors/newSingleThreadExecutor)) 

(def jobs (atom {})) 

(defn submit-job [func] 
    (let [job-id (str (java.util.UUID/randomUUID)) 
     callable (reify Callable (call [_] (func))] 
    (swap! jobs assoc job-id (.submit job-executor callable)) 
    job-id)) 

(use 'compojure.core) 

(defroutes app 
    (POST "/jobs" [& params] 
    (let [id (submit-job #(analyze params))] 
     {:status 201 :headers {"Location" (str "/jobs/" id)}})) 
    (GET "/jobs/:id" [id] 
    (let [job-future (@jobs id)] 
     (if (.isDone job-future) 
     (.get job-future) 
     {:status 404})))) 
+2

'निष्पादक सेवा' को 'भविष्य में' भविष्य में बदल दिया जा सकता है? – neoascetic

2

ऐसा लगता है कि मेरी अपेक्षा की जा रही है, लेकिन यह अपेक्षाकृत गैर-मूर्खतापूर्ण प्रतीत होता है। किसी के पास इस बारे में विचार है कि इसे कैसे सुधारें?

;; Create a unique identifier 
(defn uuid [] (str (java.util.UUID/randomUUID))) 

;; Create a job-queue and a map for keeping track of the status 
(def job-queue (ref clojure.lang.PersistentQueue/EMPTY)) 
(def jobs (atom {})) 

(defn dequeue! [queue-ref] 
    ;; Pops the first element off the queue-ref 
    (dosync 
    (let [item (peek @queue-ref)] 
     (alter queue-ref pop) 
     item))) 

(defn schedule-job! [task] 
    ;; Schedule a task to be executed, expects a function (task) to be evaluated 
    (let [uuid (uuid) 
     job (delay task)] 
    (dosync 
     (swap! jobs assoc uuid job) 
     (alter job-queue conj job)))) 

(defn run-jobs [] 
    ;; Runs the jobs 
    (while true 
    (Thread/sleep 10) 
    (let [curr (dequeue! job-queue)] 
     (if-not (nil? curr) (@curr))))) 

(.start (Thread. run-jobs)) 
0

आपका विवरण एक से अधिक उत्पादक और एकल उपभोक्ता परिदृश्य की तरह दिखता है। नीचे एक उदाहरण कोड (जो आप बाकी सामान के साथ हुक कर सकते हैं और संभवतः कुछ अपवाद तो हैंडलिंग कि एजेंट मृत नहीं मिलता है)

(def worker (agent {}))                                

(defn do-task [name func]                                
    (send worker                                  
     (fn [results]                                 
      (let [r (func)]                                
      (assoc results name r))))) 

;submit tasks                            
(do-task "uuid1" #(print 10))                               
(do-task "uuid2" #(+ 1 1)) 

;get all results 
(print @worker)