Description
I've been using Tesla in anger in the past few days, and while I do like the implementation in general, one aspect I've come to question is that it's using exceptions for it's internal error signaling.
env
is a functional context, essentially an accumulator, and the plugs form a functional transformation stack. But the functional paradigm is broken with exceptions, because they are an independent communication channel.
Imagine the following: you want to track the exact sequence of how a remote call was completed (including retries and their errors), by storing an event history. Because you're using retries, you want to log events under the retry handler - as well as above it to log the final result. The final result isn't independent of the retries independent because of POST calls. So now you need to know in the Middleware above the retry handler something about what errors have happened during retry. For example, the first exception could be a :timeout
which means you don't know if the POST succeeded or failed at the endpoint, but the next retry gives you a :econnrefused
which would indicate 'state at endpoint is unchanged'. Just by looking at the final :econnrefused
you don't know the entire story, you need to keep track of some state from the previous tries. However because :econnrefused
leads to an exception, any state stored in env is not accessible at the upper layers of middleware, so the obvious choice of tracking cumulative effect of the retries in Env doesn't work.
My current workaround is to store the state information that I need using Process.get
and Process.set
, but that's pretty ugly.
Any chance of changing the design of Tesla, to use just the env internally for error signaling, and have an Exception Middleware that can raise Exceptions at the end if desired? IMO it's a more unified and flexible design going forward.