h2non/toxy

Mid-request poison udpates

Closed this issue · 5 comments

I have implemented a custom throttling solution with node, but I am interested in using toxy. One of the features I need is the ability to begin throttling a request mid stream. In other words, if I am streaming a large video, I need to be able to start throttling the bandwidth some amount of time (say 10 seconds) into the stream to simulate poor network conditions. I see that I could create a poison to throttle the request and use the toxy API to asynchronously activate the poison, but my question is: will the poison immediately take effect (mid request) or will it not take effect until future requests arrive?

h2non commented

Short answer: poisons, and more specifically, that kind of poison, are applied atomically to the whole incoming HTTP request transaction in the server. At this time you can't do that using the built-in poison.

Solution: there're multiple ways to achieve what you're looking for, and it's not complex. I can draw two different approaches:
a) the most interesting and versatile choice for you would be creating you're own poison, and then implement there all the logic you're looking for without legacy constraints. You can do that in multiple ways, and also using third-party modules, and even one I wrote evil purposes like this.
b) I would like to provide more versatility to the throttle poison, so I'm fully open to accept PRs that improves toxy. As start point, we could just extend the poison options to allow the user to change the throttle behavior in the meantime it's processed, so for instance, passing an option to specify the bytes burst concurrency level, and more stuff taking some ideas from common QoS patterns.

Sounds good! Thanks for the quick response!

h2non commented

I thought a bit about this... and actually the current throttle implementation won't be valid for persistent HTTP connections, like in your case doing video streaming.

The current throttle poison implementation is not too much smart, and it's mostly for fixed length bodies, specially for small ones (< 1MB), since the whole body will be buffered in memory, and then sliced into small chunks and sent over the network slowly.

I would suggest, based on your requirements, moving with the first approach and create a custom "throttle-like" poison which performs a progressive bytes throttling strategy based on a simple FIFO queue, caching exclusively the pending chunks until the next queue drain interval is dispatched, and finally sending them over the network.

Right. My custom throttling implementation does this using node Streams. Usage looks like:

var throttler = new Throttler();
request('http://some-video-url.com').pipe(throttler).pipe(res);
setTimeout(function() {
    throttler.setBitrate(1000);
}, 5000);

To use troxy, I would have to convert my Stream based implementation to a middleware based troxy poison.

h2non commented

That's the recurrent approach to do that: piping the producer into another stream producer which handles the data flow.

Unfortunately that cannot be done in the toxy scope, since you can't produce another stream, so you've to rely on mutation of the http.IncomingMessage object to intercept the stream flow, like throttle poison does.