-
Notifications
You must be signed in to change notification settings - Fork 350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Timeout bigger than 5s does not work with hackney adapter #151
Comments
Right, currently the workaround would be to use for example adapter :hackney, recv_timeout: 30_000 The general solution would mean "a middleware can set adapter-specific options" which does not sound good. A specific one would be to default hackney timeout to infinity unless overridden but I'm not 100% sold on that idea. |
Maybe we could use the Middleware timeout to add adapter specific timeouts too |
The default could be to set the adapter specific timeout configuration to 500 milliseconds ahead of the middleware timeout. The adapter timeout would work as a "backup" and would not conflict with the Middleware behaviour. But I think the best way to do that would be to extend the adapter interface to include a generic configuration to connection and request timeouts. So it would be adapter responsability to translate the generic timeout configuration to the client, and the middleware would use the adapter configuration instead of knowing the client specifics about timeout configuration. What do you guys think? |
For those hit this problem but with |
Note for 1.0 users: You need to wrap adapter opts under adapter :hackney, recv_timeout: 30_000
# or
MyClient.get("/", opts: [adapter: [recv_timeout: 30_000]]) |
I'm not experiencing this issue. Tesla 1.2.1 Using it like this: middleware = [
{Tesla.Middleware.Timeout, timeout: timeout}
]
client = Tesla.client(middleware)
Tesla.get(client, url, opts) I get the timeout I expect both for timeout values below and above 5s. |
Is there any solution for this one? I have tried all the approaches and still facing the same issue. |
I got hackney working with this as middleware, it works - I'm pulling in a 10 second request from Tesla.
|
This is exactly what I expected Tesla.Middleware.Timeout to do: set the appropriate timeout option for each adapter or implement one if the adapter doesn't have one. I wonder how many users out there have set a timeout value but don't realize it isn't having the effect they expect because they haven't encountered a failure case yet? And when they do, they'll be rather confused why the timeout behavior works as expected when they disable their chosen adapter and are using :httpc which has a default timeout of infinity, thus the Tesla.Middleware.Timeout does what they expect? If there really is no appetite for making Tesla translate common options to the backend adapters please rename Tesla.Middleware.Timeout to something else like Tesla.Middleware.CircuitBreaker. edit: not trying to be harsh, just want to help others avoid this issue. Thanks for making Tesla! |
For anyone reaching this thread , in 1.4.0 the syntax in suggested fixes was not working for me. I got the Hackney timeout to work by passing the adapter module and options in as a tuple defmodule MyModule do
use Tesla
adapter({Tesla.Adapter.Hackney, recv_timeout: 30_000})
...
or config.exs config :tesla, adapter: {Tesla.Adapter.Hackney, recv_timeout: 30_000} |
Hey peeps, I am going to close the issue for now. The situation is trivial to fix in your app compared to the complexity of changing the behavior since it will create a lot of coupling between the adapters and this particular middleware. Feel free to open a PR with your proposed solution if you feel strongly about it. For future reference, people need to pay attention to the configuration of the adapter and the middleware combination; therefore:
So you need to configure the values on your end to ensure they are working as intended. |
Leaving a note, we will try to address the situation by reserving a configuration for such value. |
Thank you @austinarbor, that worked like a charm! I had to use the first strategy since the second strategy would be overwritten by my test config which uses the Tesla Mock adapter. |
@feld I would love to provide some Circuit Breaker middleware if possible. I keep returning to this.
I feel the answer should definitely be "NO." However, the middleware could set a reserved option for the adapter to read from.
Yes, I am thinking on adding another optional callback that could tell the "features" a given adapter implements; Pseudo-code: defmodule Tesla.Middleware.Timeout do
@behaviour Tesla.Middleware
@default_timeout 1_000
@impl Tesla.Middleware
def call(env, next, opts) do
timeout = Keyword.get(opts, :timeout, @default_timeout)
with adapter <- Tesla.Client.adapter(env.__client__),
true <- adapter != nil,
true <- function_exported?(adapter, :features, 0),
features <- apply(adapter, :features, []),
true <- :timeout in features do
env
|> Tesla.put_new_opt(:timeout, timeout)
|> Tesla.run(next)
else
_ -> run_task(env, next, opts)
end
end
defp run_task(env, next, opts) do
# ...
end
end @teamon what do think about this one? |
In hackney version 1.3.1 they've reduced the default
recv_timeout
from infinity to 5s (source)So, if you use
Tesla.Middleware.Timeout
with timeout bigger than 5s hackney will timeout regardless of your timeout.A solution is to pass that
recv_timeout
to hackney's request method as HTTPoison doesThere is no problem with the default
httpc
adapter as its default timeout isinfinity
The text was updated successfully, but these errors were encountered: