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

Send back response data while still processing #1466

Open
bilbothebaggins opened this issue Jan 10, 2025 · 6 comments
Open

Send back response data while still processing #1466

bilbothebaggins opened this issue Jan 10, 2025 · 6 comments

Comments

@bilbothebaggins
Copy link

I wanted to implement a very simple HTTP server to query some large/slow datasets in our buildsystem.
This means that generating the data for a GET request can take many seconds.

I noticed that the programming model with all Write-PodeXXXResponsefunctions - most collapsing to Write-PodeTextResponse as far as I can tell - is to collect all the data and then send back the headers and body in one go at the end of the route.

This is quite inconvenient in my case.
I would have preferred to be able to send the response data incrementally.

A hypothetical API:

# Do some input validation
...
# Start fetching data
...
# Send response headers (it's fine to do this in one block)
Write-PodeHeaders ...
while (...) {
  # Once data available
  Write-PodeBodyTextPart $firstPartOfData
  ...
}
...

I know I could start fiddling with Response.Send() or the underlying request, but it seems this would be very flaky.

Am I maybe missing something?

@mdaneri
Copy link
Contributor

mdaneri commented Jan 12, 2025

@bilbothebaggins
Copy link
Author

Use https://badgerati.github.io/Pode/Tutorials/Routes/Utilities/SSE/ for that

Thanks for the tip.

I note at first glance:

For a request to be convertible, it must have an Accept HTTP request header value of text/event-stream

Did you mean to say SSE would be a drop-in, or rather that the use-case can be adapted to use SSE?

@mdaneri
Copy link
Contributor

mdaneri commented Jan 13, 2025

I responded a bit hastily. SSE is a web browser feature. If you need to feed a webpage with data, this is the most technically sound solution to use. However, if your request is not coming from a web page, other methods like a multipart stream can be employed.

@bilbothebaggins
Copy link
Author

Hmm ... isn't multipart/form-data an upload feature?

@Badgerati
Copy link
Owner

Hi @bilbothebaggins,

SSE would be the best case, but it depends on how where you're going to call the Route, and how you're going to handle the data as it's streamed back from the server:

  • If this is for a website, SSE would work best as you can have the data be streamed back to the client and render it as it coming in.
  • If this is an API to be called via CLI, then SSE would "work", but typically Invoke-RestMethod will just block until all data is received and the connection closed.

@bilbothebaggins
Copy link
Author

* If this is an API to be called via CLI, then SSE would "work", but typically `Invoke-RestMethod` will just block until all data is received and the connection closed.

It's a mixed bag ... it's an API call to populate a dynamic dropdown on a Jenkins CI Job Parameter.
So technically it is an API call that I cannot influence much.
But on the user side it is influencing load performance of the site.

Anyways ... since this was even slower than I anticipated, I had to implement some caching anyway.

I might as well outline this for future readers:

  • Incoming GET requests on that API endpoint are hashed (json-ify the $WebEvent.Query and generate an MD5 hash) to uniquely identify each request.
  • If a previously generated data set is already here (as keyed by the hash)
    • Asynchronously (Start-ThreadJob) re-start the data generation
    • return the previous data immediately.
  • Otherwise wait for the data and synchronously return it.

A bit involved, but it worked fine for this endpoint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Backlog
Development

No branches or pull requests

3 participants