dramatiq icon indicating copy to clipboard operation
dramatiq copied to clipboard

Is using lazy_loader a good idea - integrating dramatiq into django, flask, cement and others

Open TomFreudenberg opened this issue 5 months ago • 2 comments

Issues

Working on an app while using Cement framework, I need the option to lazy bind the actors after the broker setup is done.

What OS are you using?

macOS Ventura

What version of Dramatiq are you using?

v1.15.0 (from pip install)

What did you do?

Example layout

- controller.py
+ actions /
  - __init__.py
  - tasks.py
tasks.py
import dramatiq
import requests

@dramatiq.actor(queue_name='count_words')
def count_words(url):
    response = requests.get(url)
    count = len(response.text.split(" "))
    print(f"There are {count} words at {url!r}.")

When using this in a Cement controller, the code will fail, while the broker is not setup when module gets imported.

controller.py
from cement import Controller, ex
import .actions as actions

class Demo(Controller):

    def example(self):
        actions.tasks.count_words.send('https://github.com')

That will fail, because the app hook to initialze the broker was not run when module actions was imported and actors had applied.

What did you expect would happen?

Lazy load of the actors so that the broker setup can run before

def register_rmq(app):
    rabbitmq_broker = RabbitmqBroker(url="amqp://user:test@localhost:5672/")
    dramatiq.set_broker(rabbitmq_broker)

How to solve?

I found a solution in using the package scientific-python/lazy_loader:

Apply lazing loading to the actions module does solve the whole problem.

actions/init.py
import lazy_loader as lazy

__getattr__, __dir__, __all__ = lazy.attach(
    __name__,
    submodules=['tasks']
)

With just that piece of code in the __init__.py of the actions package, the module is loaded only on first access of any function.

Here, when using:

actions.tasks.count_words.send('https://github.com')

At that time also the broker is initialized.

How to continue?

Wouldn't that be an good solution for dramatiq_django and dramatiq_flask as well?

Or, is there any parts I missed why this is not a good solution?

TomFreudenberg avatar Jan 14 '24 03:01 TomFreudenberg