Skip to content
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

Making requests with timeout #10

Open
johtso opened this issue Jun 10, 2024 · 7 comments
Open

Making requests with timeout #10

johtso opened this issue Jun 10, 2024 · 7 comments

Comments

@johtso
Copy link

johtso commented Jun 10, 2024

Specifying a timeout when making a web request seems like a core feature, otherwise your code is at the whim of whatever you're communicating with.

Usually I'd pass a AbortSignal.timeout(time) in the fetch options.

Another solution would be to race the promise with setTimeout. Doesn't look like the promises package exposed race functionality though.

Possibly linked with #4.. depending on the approach

Related:
gleam-lang/javascript#11
gleam-lang/javascript#10

@lpil
Copy link
Member

lpil commented Jun 10, 2024

Good idea. What might the API be?

@johtso
Copy link
Author

johtso commented Jun 10, 2024

Good idea. What might the API be?

Possibly gleam/javascript or plinth should expose AbortController/AbortSignal, and then if this package supported passing options with the request then we could just do that.

That would basically just be replicating the javascript way of doing it though.

Not sure if we want to expose friendlier APIs, or just stick with the most javascripty way.

@lpil
Copy link
Member

lpil commented Jun 10, 2024

For any package I maintain all APIs must be designed with Gleam in mind, in order to get the best experience for the language.

@johtso
Copy link
Author

johtso commented Jun 10, 2024

Okay, well, in that case I guess the first question is what functionality we want to expose.

At its simplest, javascript's signal approach gives you a function that you can call to abort the request.
AbortSignal.timeout(ms) just gives you a signal that is automatically aborted after that time.

You can also combine signals using AbortSignal.any(...signals), for example if you want a timeout, but also the ability to explicitly abort the request.

Not sure what you think about this API suggestion for manipulating options? #5

Based on that, my first thought was something like:

let #(abort, options) = fetch.with_abort_signal(options)
fetch.with_timeout(options, 5000)

But I guess that would be awkward when it comes to chaining options functions, seeing as one wants to give you the abort function as well as the new options.

It's also a little tricky as it's not just an array of signals we can append to, they all need to be combined in one go using AbortSignal.any.

But I guess we could keep the signals in an array and then bundle them up when sending the request.. or..

...alternatively we do something like:

let #(abort, signal1) = fetch.abort_signal()
let signal2 = fetch.timeout_signal(5000)

fetch.with_signals(options, [signal1, signal2])

// and maybe a shortcut
fetch.with_timeout(options, 5000)

Anyway, that's what my gleam-novice brain managed to squeeze out 🍋

https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal
https://developer.mozilla.org/en-US/docs/Web/API/AbortController

@lpil
Copy link
Member

lpil commented Jun 12, 2024

What are some real-world use cases here? If we gather those we can see what functionality folks are largely using today in JS.

@johtso
Copy link
Author

johtso commented Jun 12, 2024

@lpil real world use cases are a great place to start!

Timeouts:

  • Making many requests and a buildup of hanging requests would tie up resources like open connections. Say web-scraping, or a worker handling a constant stream of tasks that involve making requests to external APIs.

Abort signals:

  • A user interface that allows the user to upload a large file and has a cancel button.
  • Debouncing and canceling the current request whenever something happens and firing a new request.

Combined abort signals:

  • Multiple dependent fetch requests where you want to cancel all of them if one of them fails.
  • A user interface where there can be multiple simultaneous uploads and you allow the user to cancel an individual request, or all requests. This could be neatly achieved by combining the "cancel all" signal with the specific signal for each request.

@lpil
Copy link
Member

lpil commented Jul 25, 2024

Ah thank you, I'm understanding a lot better now.

I think it would be good to introduce some configuration API and an abortcontroller type which can be optionally taken by this type. This will be more verbose in some contexts but it's the most flexible. We can add more concise functions later if need be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants