I want to poll the endpoint no faster than once per second, and no slower than the time it takes to poll the endpoint. There should not be more than one request.
I need a reactive programming method for polling an endpoint at least once per second, but if the endpoint takes more than 1 second, the next query is launched immediately.
In the marble diagram below, the 2nd and 3rd queries take more than 1 second, but the fourth and fifth queries finish faster. The next request is triggered either on the 1st border, or immediately after receiving data from the last outstanding request.
s---s---s---s---s---s---| # 1 second interval observable r---r----r--------rr---|
I am trying to get the correct terminology on a marble diagram, so I am assuming that the beginning of the endpoint queries should be marble. I am the sticker “r”, and the marble event for which I mark “d” has data about the endpoints.
Here is how much code I needed to do in plain js; however, subsequent requests do not work immediately after receipt, as I said above.
var poll; var previousData; var isPolling = false; var dashboardUrl = 'gui/metrics/dashboard'; var intervalMs = updateServiceConfig.getIntervalInMilliSecondForCharts(); return { startInterval: startInterval, stopInterval: stopInterval }; function startInterval() { stopInterval(); tryPolling(); // immediately hit the dashboard // attempt polling at the interval poll = $interval(tryPolling, intervalMs); } /** * attempt polling as long as there is no in-flight request * once the in-flight request completes or fails, allow the next request to be processed */ function tryPolling() { if (!isPolling) { isPolling = true; getDashboard() // if the dashboard either returns successful or fails, reset the polling boolean .then(resetPolling, resetPolling); } } /** there no longer an in-flight request, so reset the polling boolean */ function resetPolling() { isPolling = false; } function stopInterval() { if (poll) { $interval.cancel(poll); poll = undefined; } } function getDashboard() { return restfulService.get(dashboardUrl) .then(updateDashboard); } function updateDashboard(data) { if (!utils.deepEqual(data, previousData)) { previousData = angular.copy(data); $rootScope.$broadcast('$dashboardLoaded', data); } }
source share