|
1 | 1 | import datetime |
2 | 2 | from bson import ObjectId |
| 3 | +from redis.exceptions import LockError |
3 | 4 | import time |
4 | | -from .exceptions import RetryInterrupt, MaxRetriesInterrupt, AbortInterrupt |
| 5 | +from .exceptions import RetryInterrupt, MaxRetriesInterrupt, AbortInterrupt, MaxConcurrencyInterrupt |
5 | 6 | from .utils import load_class_by_path, group_iter |
6 | 7 | import gevent |
7 | 8 | import objgraph |
@@ -70,6 +71,12 @@ def __init__(self, job_id, queue=None, start=False, fetch=False): |
70 | 71 | elif fetch: |
71 | 72 | self.fetch(start=False, full_data=False) |
72 | 73 |
|
| 74 | + @property |
| 75 | + def redis_max_concurrency_key(self): |
| 76 | + """ Returns the global redis key used to store started job ids """ |
| 77 | + return "%s:c:%s" % (context.get_current_config()["redis_prefix"], |
| 78 | + self.data["path"]) |
| 79 | + |
73 | 80 | def exists(self): |
74 | 81 | """ Returns True if a job with the current _id exists in MongoDB. """ |
75 | 82 | return bool(self.collection.find_one({"_id": self.id}, projection={"_id": 1})) |
@@ -274,7 +281,27 @@ def perform(self): |
274 | 281 |
|
275 | 282 | self.task.is_main_task = True |
276 | 283 |
|
277 | | - result = self.task.run_wrapped(self.data["params"]) |
| 284 | + try: |
| 285 | + lock = None |
| 286 | + |
| 287 | + if self.task.max_concurrency: |
| 288 | + |
| 289 | + if self.task.max_concurrency > 1: |
| 290 | + raise NotImplementedError() |
| 291 | + |
| 292 | + # TODO: implement a semaphore |
| 293 | + lock = context.connections.redis.lock(self.redis_max_concurrency_key, timeout=self.timeout + 5) |
| 294 | + if not lock.acquire(blocking=True, blocking_timeout=0): |
| 295 | + raise MaxConcurrencyInterrupt() |
| 296 | + |
| 297 | + result = self.task.run_wrapped(self.data["params"]) |
| 298 | + |
| 299 | + finally: |
| 300 | + if lock: |
| 301 | + try: |
| 302 | + lock.release() |
| 303 | + except LockError: |
| 304 | + pass |
278 | 305 |
|
279 | 306 | self.save_success(result) |
280 | 307 |
|
|
0 commit comments