When you develop an app which communicates with the backend over HTTP requests, handling unsuccessful requests is straightforward: you send a request and you get a response. Based on the response you can detect whether your request was valid or if the server crashed as a result of it.
With Phoenix channels, it’s a bit different. You still send a message and get a response back, but if your message crashes the channel, you don’t get the response and your only hope is the onError
hook, which most probably lives in a different place than the code which sent the message.
As of now, our frontend app keeps the knowledge about the state of the channels it uses (whether the channels have been joined or if they crashed). If one of the channels crashes, the app replaces the whole screen with a big spinner which makes the user wait until the connection is reestablished.
The app has to do that, because the library for handling submitting forms is based on promises. If the message (which was a result of submitting the form) crashed the server, the promise for sending the form data will never get resolved. In this case, we have to destroy the form component to reset its state (otherwise it’d be stuck at “submitting” state).
Now, I’m not particularly fond of this solution. Mainly because the onError
hook is called not only when the channel crashes, but also when the connection is abruptly stopped – that happens very often, especially when you’re on mobile and you open the app in the browser and then close the browser and open it again.
In short, I’d rather have my app to deal with errors when they happen as a result of user action (like in the HTTP example) rather than having a big wooly error handler (the spinner) for the whole app. I don’t want to disrupt the user experience if the connection is temporarily dropped and I still want to precisely handle server failures, but I don’t quite know how to approach that with the available tools.
Do you have any tips on how to design frontend apps to handle such error cases? Should I change my thinking and get over the fact that the semantics of HTTP requests and Phoenix channels are vastly different?
I already read the docs about channels and the source code of the frontend client.