Signals: Async/sync mixed receivers

Hello! I’ve been looking into getting some of my favorite packages ready for async.

One caveat I encountered is how to use signals, provided a package aims for a no-downsides approach to simultaneous sync & async support.


My understanding is that Signal.send() and Signal.asend() both handle mixed receivers but always wrap the “wrong” side via async_to_sync or sync_to_async.

The first (non-) issue for a library is the dispatch side, and here it seems to be easy and one has to just use Signal.send() and Signal.asend() for sync and async paths, respectively. Some code duplication as always, but still fine.

The second issue is on the receiver-side, which seems a bit more difficult. Basically it boils down to: Which version of the handler should we connect: sync or async?

I’ve considered workarounds like having a config in the packages for this which decides for a project whether to prefer sync or async handlers, e.g. ASYNC_FIRST = True, but that would be a bit manual and would not be ideal for preject where there is mixed sync and async.

Ideally we would be able to connect both, and Django’s signal dispatcher would use the more fitting one depending on how it was called.

signal.connect(do_something_on_save)
signal.connect(ado_something_on_save, pair=do_something_on_save)

I’m wondering whether my reasoning is correct or whether I’m missing something.

1 Like

Hey :waving_hand:

We’d need something along the same lines for https://github.com/Arfey/django-async-backend. I’ve also drafted a DEP here: https://github.com/django/deps/pull/103. Any thoughts are welcome.

1 Like

Thanks for the response!

So one thing I obviously missed was DEPs :slight_smile: .
I’ll chime in there and maybe I can contribute something.

1 Like