Channels/websockets/Daphne not working consistently on iOS Chrome mobile

I have a simple Django app running on Raspberry Pi and I am using Apache Web Server with Daphne (pi is the web server, too).

The Django app shares readings of a heat/temp sensor that is connected to the pi. It cycles every 1 minute and using websockets updates the browser of the connected device.

I can successfully connect using the raspberry pi IP with my other devices on the network including Windows desktop with Chrome, Macbook with Safari and the pi itself with Chromium. I can’t reliably connect with my iPhone running Chrome mobile. For the iPhone the best it can do is connect the first time but then Daphne shows this error; WARNING Application instance <Task pending name=‘Task-1’ coro=<ProtocolTypeRouter.call() running at /home/pi/.local/lib/python3.9/site-packages/channels/routing.py:62> wait_for=<Future pending cb=[_chain_future.._call_check_cancel() at /usr/lib/python3.9/asyncio/futures.py:384, <TaskWakeupMethWrapper object at 0x747b2c10>()]>> for connection <WebSocketProtocol client=[‘127.0.0.1’, 38802] path=b’/ws/showConditions/'> took too long to shut down and was killed.

I am happy to share code but could someone help me on where to focus the root cause analysis?

I read on one post that iPhone requires SSL. Tried that but could not get it to work.

I also am not actually using channels - should I add Redis to the app and that would fix it? At present I can only have one device connected at a time, which is fine. I assume using channels would allow multiple devices to connect?

Lastly, is it just a question of a timeout error and I just need to adjust a setting somewhere? I’ve seen other posts like this where NGINX was being used and they adjusted a NGINX timeout setting and it fixed it. Not sure if Apache might have a similar setting that needs to be tweaked.

Channels (basically) handles IPC between consumers (and workers, which can be thought of as a type of consumer). For example, it’s what allows one connected device to communicate with another connected device.

If no connected device needs to communicate with any other connected device, and, there’s no need for an external process (such as your primary Django app) to communicate with a consumer, then I believe you are correct - there’s no need for the Channels layer. (I don’t think I’ve ever used it that way, but I don’t know any reason why it wouldn’t work.)

If I had to diagnose something like this, the first thing I’d do is examine and evaluate the requests being issued. See if there’s something materially different between what the iPhone is sending vs other clients.

Is the iPhone communicating through wifi or cell? If it’s cell, there may be an issue there. See if you can try it with wifi.

I don’t have an iPhone, but I do have an iPad. I regularly use it to connect to a channels-based instance, but that’s always wifi, and almost always using Chrome (not Safari).

You mention you’re using Apache - are you using it as a proxy for the websockets?, or are the clients connecting directly to the Daphne instance?

Side note, I have only ever used nginx with websockets and have only ever deployed nginx on a Pi. I’ve never tried to use Apache in either of those situations.

If you’re using Apache as a proxy, it _may be worth swapping it out for nginx. And, you could also try swapping out uvicorn for Daphne.

Do you have another computer that you can test this on instead of the Pi? There may be platform differences involved.

It’s not that I’m necessarily suggesting these as solutions, but it may help identify which component is causing the problem.

You mention a delay here. How long does the connection remain active before the error message? Is it a reasonably consistent time interval? That may be useful information to determine.

Thanks Ken for the quick and detailed reply.

I checked the iPhone - its on wifi because it has to be on the network to get to the site. Turning off the cell coverage had no impact.

Apache is handling the http requests but is configured to redirect to ASGI for the websockets.

I am going to uninstall Apache and install NGINX and see if that works better. I should probably just have done that anyway but it was a pain getting Apache to work so I was a little gun shy but NGINX does seem to be a far more popular choice in the various forums.

Thanks again.

Actually, this is one of the primary reasons we completely switched from Apache to nginx. Getting nginx to work for us with websockets was so much easier than Apache. See Using NGINX as a WebSocket Proxy and WebSocket proxying.

Thanks for the links. I’ll check those out next. I did some troubleshooting based on your previous suggestions and it looks like mobile actually does work but as soon as the phone goes to “sleep” the Daphne process gets killed, but, it does not shut down properly and so fails to reconnect with the browser once the phone is re-awakened and the browser refreshed.

More accurately, I would guess that the phone drops the TCP socket underlying the websocket. Apache / nginx then recognizes that the TCP socket has been dropped, and notifies Daphne that the connection no longer exists. Daphne would then perform the cleanup, including the deletion of the consumer.

Is one way to troubleshoot the issue with the dropped TCP socket to disconnect the websocket as soon as the webpage is populated, then next time the page needs an update, connect another websocket? I mirrored my code off a realtime graphing application, but, my process only populates every X minutes (currently set to 1 minute and will likely move to 5 minutes once up and running). Keeping a websocket open for that long with no activity seems like a bad idea?

What is the acceptable time delay between the time the data is updated and the time it needs to be displayed?

How many devices are connecting to this server to get this data?

If the number of devices is bounded and limited (say, no more than 5), I’d forego the entire websocket portion of this and just have the device poll the server once a second or so. (Time delay dependent upon your answer to the first question.)

Keep in mind that the server cannot open a websocket. It can’t (generally) open a socket to a client at all. The HTTP protocol is a “pull”, not a “push” environment. It would be up to the phone to detect that the connection has been dropped and to reestablish it.

But no, there’s nothing intrinsically wrong with long-open sockets, provided any timeout-related factors are addressed.

I think the point in paragraph 3 clarifies my next steps. It’s a site that will only ever have 1-2 devices connected and time delay for a couple seconds is no problem. Websockets are pretty cool but probably overkill for this application. Thank you Ken for your advice and guidance.