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

FR: Callback when response is written #1671

Open
Jille opened this issue Nov 29, 2023 · 7 comments
Open

FR: Callback when response is written #1671

Jille opened this issue Nov 29, 2023 · 7 comments

Comments

@Jille
Copy link
Contributor

Jille commented Nov 29, 2023

I want to use Response.SetBodyRaw(), but I need to know when it's safe to deallocate the buffer. I'm writing a cache server and doing memory management manually.

Would you be opposed to adding a callback that I can configure? Something like:

func (r *Response) SetCompletionCallback(callback func()) {
  r.completionCallback = callback
}

which then gets called after the request has completed (and it is thus safe for me to free the body)

@erikdubbelboer
Copy link
Collaborator

Are we talking about a server handler or a client response?

@Jille
Copy link
Contributor Author

Jille commented Nov 29, 2023

Server handler

Groetjes,

@pisken
Copy link

pisken commented Nov 30, 2023

I think this is good feature, for some server applications that handle large of requests and the buffer was cached, using SetBodyRaw to get high performance but currently, will unsafe release the buffer.
Quick to workaround push the buffer that need release into batcher and process in the after.

If support callback or closer interface,... when write the response body completed get will helpful in this case.

@Jille
Copy link
Contributor Author

Jille commented Dec 1, 2023

I've looked at the code for a bit and I think that my use-case is satisfied by using SetBodyStream() and passing an io.Closer, which gets called when I can free my underlying data.
As far as I can see (by reading the source) both cause exactly one copy when my data gets copied into the writeBuffer to be sent to the client.

Would that work for you too @pisken?

@pisken
Copy link

pisken commented Dec 2, 2023

I see SetBodyStream not resolve for large of requests when data body available (caching), and SetBodyRaw can resolve for this case.
In this case large of request and data body response was cached, I need write body direct to connection client, no copy to other buffer to keep low memory and cpu used.

@Jille
Copy link
Contributor Author

Jille commented Dec 2, 2023

AAUI it actually copies in exactly the same scenarios.

There is always a *bufio.Writer (managed by a sync.Pool): https://github.com/valyala/fasthttp/blob/master/server.go#L2407 So during the writing of the request, that memory is allocated.

Write gets that *bufio.Writer which already has the headers written to it.
bodyBytes returns the []byte that you passed to SetBodyRaw, and then writes it to the *bufio.Writer. Unless 1) the *bufio.Writer is empty, and 2) your []byte is larger than its size, it'll copy the data.

You can ensure the buffer is empty by setting ImmediateHeaderFlush on the response, but that's at the cost of an extra syscall (for non-HTTPS), which might or might not be more expensive than copying the bytes.

For SetBodyStream (assuming you've set the contentLength), you'll end up in writeBodyStream here which will call io.CopyBuffer(), which will call YourBodyStream.WriteTo, which can do a single large write, just like the SetBodyRaw case.

@erikdubbelboer
Copy link
Collaborator

Sounds like a good idea, a pull request is welcome!

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

3 participants