I'm writing a PSGI middleware and currently running on the Twiggy server. The middleware deals with large (>2GB) dynamically created files and utilising the asynchronous streaming ability of Twiggy/AnyEvent.
The PSGI Specification says very briefly in regards to streaming responses:
... the responder MUST return yet another object which implements
write
andclose
methods. ...
Digging through the Twiggy code, it uses AnyEvent::Handle::push_write
to implement the above write
method. This will eat all your RAM if you keep feeding it large amounts of data faster than you can write it out to the network though.
Of course AnyEvent::Handle
has methods and utilises callbacks to deal with buffer size (ie on_drain
event handler to indicate when write buffer is empty and wbuf_max
to limit the write buffer size).
However using these features would be very server specific and limit the portability of a PSGI application. The PSGI spec doesn't seem to cover an API for controlling/monitoring asynchronous write streams or accessing the underlying filehandle/descriptor for manual checking.
How do others address memory usage/buffering or knowing when the asynchronous write is complete in a way which which is 'compatible' across PSGI web servers? Any pointers would be great.
As a follow up, I thought I would post a simplified version of how I got around my issue in case it helps someone else.
Using the
{handle}
element in theAnyEvent::Handle
used inwriter
, I manually set the callbacks foron_drain
andon_error
.The
on_drain
is called when the write buffer is empty. So the handler enables my data generation code to continue generating data.When the data generation callback is called, data is written to the response and it disables/pauses the data generation.
The cycle continues when the
on_drain
handler once again enables the data generation.This keeps the memory usage of the
writer
in check, using minimum memory now to process the large streaming responses. I still seem to have some slow leaking memory issues, but that is probably deep I'm my code elsewhere.