I have resolved the error message by replacing the above line with:
self.base_send = send
It works, or at least I no longer receive that error and my system is functioning exactly as expected with this change.
(Side bar: My websocket consumer is async. If this change adversely affects a synchronous websocket listener, I wouldn’t see it.
I know that in previous iterations - before making this change to consumer.py, I would not get the error message in a WebsocketConsumer.)
I’ve followed the logic all the way back to asgiref.server.StatelessServer, and this is where I get lost. I don’t understand where the self.application_send is coming from in get_or_create_application_instance so I’m not sure where to look beyond this.
… which is the same as the adjustment you’ve made manually.
So the question is where/how/why is self._syncFalse here? — I guess I’d throw a breakpoint in at that line and and double check everything is as expected.
There’s not really enough to see the problem here.
Follow-up note on the original with a little more information and to try to improve clarity:
I am talking about a SyncConsumer being used as a “background worker” process.
As a background worker process, it only communicates through the channel layer
It will never communicate directly with a websocket
Therefore, it doesn’t useself.send or self.base_send
All this means that the error message occurs when the instance of the SyncConsumer is created by the runworker process. It does not affect the operation of that consumer.
So, in thinking about it some more, I could just live with the warning message.
(It just “bugs” me - pun intended - but I guess that’s on me.)
I’ve lost myself there: I read the Boolean logic backwards, as always.
OK, yes, I see you…
…I could just live with the warning message.
Mmmm. send is an asyncio.Queue.put right? That should be detectable as a coroutine object, I’d think. So, there’s an interesting question as to what we’d do to get that out of AsyncToSync.__init__() without the warning.
I get this testing locally with PY310:
>>> import asyncio
>>> q = asyncio.Queue()
>>> q.put
<bound method Queue.put of <Queue at 0x10460c9a0 maxsize=0>>
>>> asyncio.iscoroutinefunction(q.put)
True
So, what is send in this case, and what Python are you on? etc.
The method base_send is being set in the block of code in the if condition we’ve been talking about. This is in the __call__ method of AsyncConsumer. (SyncConsumer inherits from AsyncConsumer).
The self.application_send appears to be coming from line 69 because I don’t see any other method named application_send defined in the class hierarchy being used here.
But that method is flagged as async:
async def application_send(self, scope, message):
"""
Receives outbound sends from applications and handles them.
"""
raise NotImplementedError("You must implement application_send()")
(The NotImplementedError being raised doesn’t concern me, because this is a background worker and does not call send.)
And this is where I’m getting lost and not really understanding what’s going on here.
Right. Yes. — We’re gonna struggle to mark that lambda as a coroutine. (Or maybe we could just assign it to a variable and set _is_coroutine = asyncio.coroutines._is_coroutine on it… )
Happy to investigate a cleanup, but, yes, this is the reason it’s a warning, not an error.
I did some research and experimenting last night. Tried a number of different things. Did not find a solution that wasn’t significantly “uglier” and “more painful” (my opinion) than what exists now. (I also learned a bit more, so it was a bit of a win regardless.)
Anyway, if I were to make any recommendation at this point, I’d suggest tossing a note into the Channels docs in the “Worker and Background Task” section documenting that this is going to happen, it’s not a “problem” needing to be addressed, and the warning message can safely be ignored.