Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
import warnings
from threading import Thread
from time import monotonic, sleep
from ..logging import get_logger
from .middleware import Middleware
from .threading import Interrupt, current_platform, raise_thread_exception, supported_platforms
class TimeLimitExceeded(Interrupt):
"""Exception used to interrupt worker threads when actors exceed
their time limits.
"""
class TimeLimit(Middleware):
"""Middleware that cancels actors that run for too long.
Currently, this is only available on CPython.
Note:
This works by setting an async exception in the worker thread
that runs the actor. This means that the exception will only get
called the next time that thread acquires the GIL. Concretely,
this means that this middleware can't cancel system calls.
Parameters:
time_limit(int): The maximum number of milliseconds actors may
run for.
interval(int): The interval (in milliseconds) with which to
check for actors that have exceeded the limit.
"""
# your option) any later version.
#
# Dramatiq is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
from ..common import current_millis
from ..logging import get_logger
from .middleware import Middleware
class AgeLimit(Middleware):
"""Middleware that drops messages that have been in the queue for
too long.
Parameters:
max_age(int): The default message age limit in millseconds.
Defaults to ``None``, meaning that messages can exist
indefinitely.
"""
def __init__(self, *, max_age=None):
self.logger = get_logger(__name__, type(self))
self.max_age = max_age
@property
def actor_options(self):
return {"max_age"}
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
import os
from ..rate_limits import Barrier
from .middleware import Middleware
GROUP_CALLBACK_BARRIER_TTL = int(os.getenv("dramatiq_group_callback_barrier_ttl", "86400000"))
class GroupCallbacks(Middleware):
def __init__(self, rate_limiter_backend):
self.rate_limiter_backend = rate_limiter_backend
def after_process_message(self, broker, message, *, result=None, exception=None):
from ..message import Message
if exception is None:
group_completion_uuid = message.options.get("group_completion_uuid")
group_completion_callbacks = message.options.get("group_completion_callbacks")
if group_completion_uuid and group_completion_callbacks:
barrier = Barrier(self.rate_limiter_backend, group_completion_uuid, ttl=GROUP_CALLBACK_BARRIER_TTL)
if barrier.wait(block=False):
for message in group_completion_callbacks:
broker.enqueue(Message(**message))
import traceback
from ..common import compute_backoff
from ..logging import get_logger
from .middleware import Middleware
#: The default minimum amount of backoff to apply to retried tasks.
DEFAULT_MIN_BACKOFF = 15000
#: The default maximum amount of backoff to apply to retried tasks.
#: Must be less than the max amount of time tasks can be delayed by.
DEFAULT_MAX_BACKOFF = 86400000 * 7
class Retries(Middleware):
"""Middleware that automatically retries failed tasks with
exponential backoff.
Parameters:
max_retries(int): The maximum number of times tasks can be retried.
min_backoff(int): The minimum amount of backoff milliseconds to
apply to retried tasks. Defaults to 15 seconds.
max_backoff(int): The maximum amount of backoff milliseconds to
apply to retried tasks. Defaults to 7 days.
retry_when(Callable[[int, Exception], bool]): An optional
predicate that can be used to programmatically determine
whether a task should be retried or not. This takes
precedence over `max_retries` when set.
"""
def __init__(self, *, max_retries=20, min_backoff=None, max_backoff=None, retry_when=None):
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# Dramatiq is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
from .middleware import Middleware
class Callbacks(Middleware):
"""Middleware that lets you chain success and failure callbacks
onto Actors.
Parameters:
on_failure(str): The name of an actor to send a message to on
failure.
on_success(str): The name of an actor to send a message to on
success.
"""
@property
def actor_options(self):
return {
"on_failure",
"on_success",
}
#: The path to store the prometheus database files. This path is
#: cleared before every run.
DB_PATH = os.getenv("dramatiq_prom_db", "%s/dramatiq-prometheus" % tempfile.gettempdir())
# Ensure the DB_PATH exists.
os.makedirs(DB_PATH, exist_ok=True)
#: The HTTP host the exposition server should bind to.
HTTP_HOST = os.getenv("dramatiq_prom_host", "0.0.0.0")
#: The HTTP port the exposition server should listen on.
HTTP_PORT = int(os.getenv("dramatiq_prom_port", "9191"))
class Prometheus(Middleware):
"""A middleware that exports stats via Prometheus_.
.. _Prometheus: https://prometheus.io
"""
def __init__(self):
self.logger = get_logger(__name__, type(self))
self.delayed_messages = set()
self.message_start_times = {}
@property
def forks(self):
return [_run_exposition_server]
def after_process_boot(self, broker):
os.environ["prometheus_multiproc_dir"] = DB_PATH
import threading
import warnings
from ..logging import get_logger
from .middleware import Middleware
from .threading import Interrupt, current_platform, raise_thread_exception, supported_platforms
class Shutdown(Interrupt):
"""Exception used to interrupt worker threads when their worker
processes have been signaled for termination.
"""
class ShutdownNotifications(Middleware):
"""Middleware that interrupts actors whose worker process has been
signaled for termination.
Currently, this is only available on CPython.
Note:
This works by setting an async exception in the worker thread
that runs the actor. This means that the exception will only get
called the next time that thread acquires the GIL. Concretely,
this means that this middleware can't cancel system calls.
Parameters:
notify_shutdown(bool): When true, the actor will be interrupted
if the worker process was terminated.
"""
def __init__(self, notify_shutdown=False):
# your option) any later version.
#
# Dramatiq is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
from threading import local
from .middleware import Middleware
class CurrentMessage(Middleware):
"""Middleware that exposes the current message via a thread-local
variable.
Example:
>>> import dramatiq
>>> from dramatiq.middleware import CurrentMessage
>>> @dramatiq.actor
... def example(x):
... print(CurrentMessage.get_current_message())
...
>>> example.send(1)
"""
STATE = local()
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# Dramatiq is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
from .middleware import Middleware
class Pipelines(Middleware):
"""Middleware that lets you pipe actors together so that the
output of one actor feeds into the input of another.
Parameters:
pipe_ignore(bool): When True, ignores the result of the previous
actor in the pipeline.
pipe_target(dict): A message representing the actor the current
result should be fed into.
"""
@property
def actor_options(self):
return {
"pipe_ignore",
"pipe_target",
}