Manage background execution of callbacks with a celery queue.
| 15 | |
| 16 | |
| 17 | class CeleryManager(BaseBackgroundCallbackManager): |
| 18 | """Manage background execution of callbacks with a celery queue.""" |
| 19 | |
| 20 | def __init__(self, celery_app, cache_by=None, expire=None): |
| 21 | """ |
| 22 | Background callback manager that runs callback logic on a celery task queue, |
| 23 | and stores results using a celery result backend. |
| 24 | |
| 25 | :param celery_app: |
| 26 | A celery.Celery application instance that must be configured with a |
| 27 | result backend. See the celery documentation for information on |
| 28 | configuration options. |
| 29 | :param cache_by: |
| 30 | A list of zero-argument functions. When provided, caching is enabled and |
| 31 | the return values of these functions are combined with the callback |
| 32 | function's input arguments, triggered inputs and source code to generate cache keys. |
| 33 | :param expire: |
| 34 | If provided, a cache entry will be removed when it has not been accessed |
| 35 | for ``expire`` seconds. If not provided, the lifetime of cache entries |
| 36 | is determined by the default behavior of the celery result backend. |
| 37 | """ |
| 38 | try: |
| 39 | import celery # type: ignore[import-not-found] # pylint: disable=import-outside-toplevel,import-error |
| 40 | from celery.backends.base import ( # type: ignore[import-not-found] # pylint: disable=import-outside-toplevel,import-error |
| 41 | DisabledBackend, |
| 42 | ) |
| 43 | except ImportError as missing_imports: |
| 44 | raise ImportError( |
| 45 | """\ |
| 46 | CeleryManager requires extra dependencies which can be installed doing |
| 47 | |
| 48 | $ pip install "dash[celery]"\n""" |
| 49 | ) from missing_imports |
| 50 | |
| 51 | if not isinstance(celery_app, celery.Celery): |
| 52 | raise ValueError("First argument must be a celery.Celery object") |
| 53 | |
| 54 | if isinstance(celery_app.backend, DisabledBackend): |
| 55 | raise ValueError("Celery instance must be configured with a result backend") |
| 56 | |
| 57 | self.handle = celery_app |
| 58 | self.expire = expire |
| 59 | super().__init__(cache_by) |
| 60 | |
| 61 | def terminate_job(self, job): |
| 62 | if job is None: |
| 63 | return |
| 64 | |
| 65 | self.handle.control.terminate(job) |
| 66 | |
| 67 | def terminate_unhealthy_job(self, job): |
| 68 | task = self.get_task(job) |
| 69 | if task and task.status in ("FAILURE", "REVOKED"): |
| 70 | return self.terminate_job(job) |
| 71 | return False |
| 72 | |
| 73 | def job_running(self, job): |
| 74 | future = self.get_task(job) |
no outgoing calls
no test coverage detected
searching dependent graphs…