diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 23915030..7afd78fa 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -67,6 +67,7 @@ of those changes to CLEARTYPE SRL. | [@5tefan](https://github.com/5tefan/) | Stefan Codrescu | | [@kuba-lilz](https://github.com/kuba-lilz/) | Jakub Kolodziejczyk | | [@dbowring](https://github.com/dbowring/) | Daniel Bowring | +| [@bagowix](https://github.com/bagowix/) | Bogdan Galushko | | [@olii](https://github.com/olii) | Oliver Nemček | | [@bartvanandel](https://github.com/bartvanandel) | Bart van Andel | | [@LincolnPuzey](https://github.com/LincolnPuzey) | Lincoln Puzey | diff --git a/examples/use_actors_from_different_files/README.md b/examples/use_actors_from_different_files/README.md new file mode 100644 index 00000000..34666618 --- /dev/null +++ b/examples/use_actors_from_different_files/README.md @@ -0,0 +1,72 @@ +# Using Actors from Different Files + +## Overview + +If you want to use actors from different files in your project, you must ensure that all +actors are properly initialized and visible to Dramatiq. This example demonstrates one +possible way to set up a project with multiple actor files and run them through the +Dramatiq CLI. + +## Project Structure + +```text +project/ +├── actors/ +│ ├── __init__.py +│ ├── bar.py +│ ├── foo.py +├── main.py +├── my_broker.py +``` + +- `actors/`: Contains actor definitions (`foo.py`, `bar.py`). +- `my_broker.py`: Initializes the broker. +- `main.py`: Application that publishes messages. + +## Steps to Run + +1. **Run the Dramatiq worker**: + +In a terminal, start a worker with the following command + +```shell +dramatiq my_broker actors +``` + +It is important to note: +* The first argument must be the module that initializes the Broker. + Because we are using a plain module name, it must call `set_broker()`. +* The subsequent arguments are extra modules to import that contain actor definitions. + In this case, only our `actors` module. + +2. **Publish tasks by running the application**: + +In another terminal, run the application that publishes some messages. +This could be a webserver, or a cron-like scheduler. +In this example it is a simple script. + +```shell +python main.py +``` + +3. **Check the logs in the Dramatiq worker terminal**: + +Back in the first terminal, check the worker logs to see that the actors have run. + +```text +Bar task done. +Foo task done. +``` + +## Conclusion + +This example is just one way of organizing actors into multiple files, but not the only way. + +The two key rules to remember are: + +1. Call `set_broker()` before importing any module that uses `@actor`. + This ensures that `@actor` will use the correct Broker. + This can be enforced by importing your broker-defining module in any actor-defining module, + like in this example. +2. Modules that are passed to the worker command line must import (directly or indirectly) + all actors. This ensures that the dramatiq worker is aware of all actors. diff --git a/examples/use_actors_from_different_files/actors/__init__.py b/examples/use_actors_from_different_files/actors/__init__.py new file mode 100644 index 00000000..24ad3e12 --- /dev/null +++ b/examples/use_actors_from_different_files/actors/__init__.py @@ -0,0 +1,7 @@ +"""Module to define actors""" + +# Import actors from submodules to ensure they are registered when this `actors` module is imported. +from .bar import bar_task +from .foo import foo_task + +__all__ = ["bar_task", "foo_task"] diff --git a/examples/use_actors_from_different_files/actors/bar.py b/examples/use_actors_from_different_files/actors/bar.py new file mode 100644 index 00000000..afa52756 --- /dev/null +++ b/examples/use_actors_from_different_files/actors/bar.py @@ -0,0 +1,9 @@ +import dramatiq + +# Import my_broker module to ensure set_broker() is called before @actor is used. +import my_broker + + +@dramatiq.actor(broker=my_broker.rabbitmq_broker) +def bar_task(): + print("Bar task done.") diff --git a/examples/use_actors_from_different_files/actors/foo.py b/examples/use_actors_from_different_files/actors/foo.py new file mode 100644 index 00000000..cf449868 --- /dev/null +++ b/examples/use_actors_from_different_files/actors/foo.py @@ -0,0 +1,9 @@ +import dramatiq + +# Import my_broker module to ensure set_broker() is called before @actor is used. +import my_broker + + +@dramatiq.actor(broker=my_broker.rabbitmq_broker) +def foo_task(): + print("Foo task done.") diff --git a/examples/use_actors_from_different_files/main.py b/examples/use_actors_from_different_files/main.py new file mode 100644 index 00000000..1c3eb495 --- /dev/null +++ b/examples/use_actors_from_different_files/main.py @@ -0,0 +1,15 @@ +# Import Broker first so it is set up. +import my_broker # noqa: F401 + +# Import actors after broker. +import actors + + +def my_app(): + """Basic application that publishes some messages.""" + actors.bar_task.send() + actors.foo_task.send() + + +if __name__ == "__main__": + my_app() diff --git a/examples/use_actors_from_different_files/my_broker.py b/examples/use_actors_from_different_files/my_broker.py new file mode 100644 index 00000000..a40569e0 --- /dev/null +++ b/examples/use_actors_from_different_files/my_broker.py @@ -0,0 +1,12 @@ +import dramatiq +from dramatiq.brokers.rabbitmq import RabbitmqBroker +from dramatiq.middleware import CurrentMessage + +# Set up Broker (and any custom Middleware) +rabbitmq_broker = RabbitmqBroker(url="amqp://guest:guest@localhost:5672") +rabbitmq_broker.add_middleware(CurrentMessage()) + +# Declare your Broker. +# IMPORTANT: This must run before importing any module that uses the @actor decorator. +# This is because @actor will immediately look up the Broker to associate the Actor with it. +dramatiq.set_broker(rabbitmq_broker)