@@ -18,7 +18,7 @@ def size(self):
1818 def list_job_ids (self , skip = 0 , limit = 20 ):
1919 """ Returns a list of job ids on a queue """
2020
21- return [str (x ) for x in self .collection .find (
21+ return [str (x [ "_id" ] ) for x in self .collection .find (
2222 {"status" : "queued" },
2323 sort = [("_id" , - 1 if self .is_reverse else 1 )],
2424 projection = {"_id" : 1 })
@@ -31,25 +31,49 @@ def dequeue_jobs(self, max_jobs=1, job_class=None, worker=None):
3131 from .job import Job
3232 job_class = Job
3333
34- if worker :
35- worker .status = "spawn"
36- worker .idle_event .clear ()
37-
3834 count = 0
3935
40- for _ in range ( max_jobs ):
36+ job_ids = None
4137
42- job_data = self .collection .find_one_and_update (
38+ # TODO: remove _id sort after full migration to datequeued
39+ sort_order = [("datequeued" , - 1 if self .is_reverse else 1 ), ("_id" , - 1 if self .is_reverse else 1 )]
40+
41+ # MongoDB optimization: with many jobs it's faster to fetch the IDs first and do the atomic update second
42+ # Some jobs may have been stolen by another worker in the meantime but it's a balance (should we over-fetch?)
43+ if max_jobs > 5 :
44+ job_ids = [x ["_id" ] for x in self .collection .find (
4345 {
4446 "status" : "queued" ,
4547 "queue" : self .id
4648 },
49+ limit = max_jobs ,
50+ sort = sort_order ,
51+ projection = {"_id" : 1 }
52+ )]
53+
54+ if len (job_ids ) == 0 :
55+ return
56+
57+ for i in range (max_jobs if job_ids is None else len (job_ids )):
58+
59+ query = {
60+ "status" : "queued" ,
61+ "queue" : self .id
62+ }
63+ if job_ids is not None :
64+ query = {
65+ "status" : "queued" ,
66+ "_id" : job_ids [i ]
67+ }
68+
69+ job_data = self .collection .find_one_and_update (
70+ query ,
4771 {"$set" : {
4872 "status" : "started" ,
4973 "datestarted" : datetime .datetime .utcnow (),
5074 "worker" : worker .id if worker else None
5175 }},
52- sort = [( "_id" , - 1 if self . is_reverse else 1 )] ,
76+ sort = sort_order ,
5377 return_document = ReturnDocument .AFTER ,
5478 projection = {
5579 "_id" : 1 ,
@@ -64,6 +88,10 @@ def dequeue_jobs(self, max_jobs=1, job_class=None, worker=None):
6488 if not job_data :
6589 break
6690
91+ if worker :
92+ worker .status = "spawn"
93+ worker .idle_event .clear ()
94+
6795 count += 1
6896 context .metric ("queues.%s.dequeued" % job_data ["queue" ], 1 )
6997
0 commit comments