I have a stream of events and I would like to call a function that returns a promise for each of those events, the problem is that this function is very expensive, so I would like to process at most n events at a time.
This pebble diagram is probably wrong but this is what I would like:
---x--x--xxxxxxx-------------x-------------> //Events
---p--p--pppp------p-p-p-----p-------------> //In Progress
-------d--d--------d-d-dd------dddd--------> //Promise Done
---1--21-2-34-----------3----4-3210-------- //QUEUE SIZE CHANGES
This is the code that I have so far:
var n = 4;
var inProgressCount = 0;
var events$ = Rx.Observable.fromEvent(produceEvent, 'click')
.map((ev) => new Date().getTime());
var inProgress$ = events$.controlled();
var done$ = inProgress$
.tap(() => inProgressCount++)
.flatMap((timestamp) => Rx.Observable.fromPromise(expensiveComputation(getRandomInt(1, 5) * 1000, timestamp)));
done$.subscribeOnNext((timestamp) => {
inProgressCount--;
inProgress$.request(Math.max(1, n - inProgressCount));
});
inProgress$.request(n);
There are two issues with this code:
- It's using the
inProgressCount
var which is updated with side effect functions. The done$ subscription is only called once when I request more than 1 item from the controlled stream. This is making theinProgressCount
var to update incorrectly, this eventually limits the queue to one at a time.
You can see it working in here: http://jsbin.com/wivehonifi/1/edit?js,console,output
Questions:
- Is there a better approach?
- How can I get rid of the
inProgressCount
variable? Why is the done$ subscription only getting called once when requesting multiple items?
Update:
Answer to question #3: switchMap is the same as flatMapLatest, so that's why I was only getting the last one. Updated the code to flatMap instead of switchMap.