mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-03-10 05:12:52 -04:00
Merge pull request #3405 from alphagov/ajax-backoff
Delay AJAX calls if the server is slow to respond
This commit is contained in:
@@ -3,6 +3,12 @@
|
||||
|
||||
var queues = {};
|
||||
var dd = new global.diffDOM();
|
||||
var interval = 0;
|
||||
|
||||
var calculateBackoff = responseTime => parseInt(Math.max(
|
||||
(250 * Math.sqrt(responseTime)) - 1000,
|
||||
1000
|
||||
));
|
||||
|
||||
var getRenderer = $component => response => dd.apply(
|
||||
$component.get(0),
|
||||
@@ -19,7 +25,9 @@
|
||||
|
||||
var clearQueue = queue => (queue.length = 0);
|
||||
|
||||
var poll = function(renderer, resource, queue, interval, form) {
|
||||
var poll = function(renderer, resource, queue, form) {
|
||||
|
||||
let startTime = Date.now();
|
||||
|
||||
if (document.visibilityState !== "hidden" && queue.push(renderer) === 1) $.ajax(
|
||||
resource,
|
||||
@@ -33,6 +41,7 @@
|
||||
if (response.stop === 1) {
|
||||
poll = function(){};
|
||||
}
|
||||
interval = calculateBackoff(Date.now() - startTime);
|
||||
}
|
||||
).fail(
|
||||
() => poll = function(){}
|
||||
@@ -49,10 +58,11 @@
|
||||
getRenderer($(component)),
|
||||
$(component).data('resource'),
|
||||
getQueue($(component).data('resource')),
|
||||
($(component).data('interval-seconds') || 1.5) * 1000,
|
||||
$(component).data('form')
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
global.GOVUK.Modules.UpdateContent.calculateBackoff = calculateBackoff;
|
||||
|
||||
})(window);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{% macro ajax_block(partials, url, key, interval=5, finished=False, form='') %}
|
||||
{% macro ajax_block(partials, url, key, finished=False, form='') %}
|
||||
{% if not finished %}
|
||||
<div
|
||||
data-module="update-content"
|
||||
data-resource="{{ url }}"
|
||||
data-key="{{ key }}"
|
||||
data-interval-seconds="{{ interval }}"
|
||||
data-form="{{ form }}"
|
||||
aria-live="polite"
|
||||
>
|
||||
|
||||
@@ -19,25 +19,25 @@
|
||||
{% include 'views/dashboard/write-first-messages.html' %}
|
||||
{% endif %}
|
||||
|
||||
{{ ajax_block(partials, updates_url, 'upcoming', interval=20) }}
|
||||
{{ ajax_block(partials, updates_url, 'upcoming') }}
|
||||
|
||||
<h2 class="heading-medium">
|
||||
In the last 7 days
|
||||
</h2>
|
||||
|
||||
{{ ajax_block(partials, updates_url, 'inbox', interval=20) }}
|
||||
{{ ajax_block(partials, updates_url, 'inbox') }}
|
||||
|
||||
{{ ajax_block(partials, updates_url, 'totals', interval=20) }}
|
||||
{{ ajax_block(partials, updates_url, 'totals') }}
|
||||
{{ show_more(
|
||||
url_for('.monthly', service_id=current_service.id),
|
||||
'See messages sent per month'
|
||||
) }}
|
||||
|
||||
{{ ajax_block(partials, updates_url, 'template-statistics', interval=20) }}
|
||||
{{ ajax_block(partials, updates_url, 'template-statistics') }}
|
||||
|
||||
{% if current_user.has_permissions('manage_service') %}
|
||||
<h2 class='heading-medium'>This year</h2>
|
||||
{{ ajax_block(partials, updates_url, 'usage', interval=20) }}
|
||||
{{ ajax_block(partials, updates_url, 'usage') }}
|
||||
{{ show_more(
|
||||
url_for(".usage", service_id=current_service['id']),
|
||||
'See usage'
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
{{ ajax_block(
|
||||
partials,
|
||||
url_for('.get_notifications_as_json', service_id=current_service.id, message_type=message_type, status=status),
|
||||
'counts',
|
||||
interval=20
|
||||
'counts'
|
||||
) }}
|
||||
|
||||
{% call form_wrapper(
|
||||
@@ -83,8 +82,7 @@
|
||||
partials,
|
||||
url_for('.get_notifications_as_json', service_id=current_service.id, message_type=message_type, status=status, page=page),
|
||||
'notifications',
|
||||
form='search-form',
|
||||
interval=20
|
||||
form='search-form'
|
||||
) }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -96,10 +96,10 @@
|
||||
</div>
|
||||
{% elif template.template_type == 'email' %}
|
||||
<div class="js-stick-at-bottom-when-scrolling">
|
||||
{{ ajax_block(partials, updates_url, 'status', interval=2, finished=finished) }}
|
||||
{{ ajax_block(partials, updates_url, 'status', finished=finished) }}
|
||||
</div>
|
||||
{% elif template.template_type == 'sms' %}
|
||||
{{ ajax_block(partials, updates_url, 'status', interval=2, finished=finished) }}
|
||||
{{ ajax_block(partials, updates_url, 'status', finished=finished) }}
|
||||
{% endif %}
|
||||
|
||||
{% if current_user.has_permissions('send_messages') and current_user.has_permissions('view_activity') and template.template_type == 'sms' and can_receive_inbound %}
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
"gulp-prettyerror": "1.2.1",
|
||||
"gulp-sass-lint": "1.4.0",
|
||||
"jest": "24.7.1",
|
||||
"jest-date-mock": "^1.0.8",
|
||||
"jest-each": "^25.3.0",
|
||||
"jshint": "2.10.2",
|
||||
"jshint-stylish": "2.2.1",
|
||||
"rollup-plugin-commonjs": "10.1.0",
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
const each = require('jest-each').default;
|
||||
const jestDateMock = require('jest-date-mock');
|
||||
|
||||
const helpers = require('./support/helpers.js');
|
||||
|
||||
const serviceNumber = '6658542f-0cad-491f-bec8-ab8457700ead';
|
||||
@@ -18,6 +21,8 @@ beforeAll(() => {
|
||||
// set up the object returned from $.ajax so it responds with whatever responseObj is set to
|
||||
jqueryAJAXReturnObj = {
|
||||
done: callback => {
|
||||
// The server takes 1 second to respond
|
||||
jestDateMock.advanceBy(1000);
|
||||
callback(responseObj);
|
||||
return jqueryAJAXReturnObj;
|
||||
},
|
||||
@@ -100,7 +105,7 @@ describe('Update content', () => {
|
||||
jest.clearAllTimers();
|
||||
|
||||
});
|
||||
|
||||
|
||||
test("It should make requests to the URL specified in the data-resource attribute", () => {
|
||||
|
||||
// start the module
|
||||
@@ -136,24 +141,6 @@ describe('Update content', () => {
|
||||
|
||||
});
|
||||
|
||||
test("If an interval between requests is specified, using the data-interval-seconds attribute, requests should happen at that frequency", () => {
|
||||
|
||||
document.querySelector('[data-module=update-content]').setAttribute('data-interval-seconds', '0.5');
|
||||
|
||||
// start the module
|
||||
window.GOVUK.modules.start();
|
||||
|
||||
expect($.ajax).toHaveBeenCalledTimes(1);
|
||||
|
||||
// units are milliseconds
|
||||
jest.advanceTimersByTime(500);
|
||||
jest.advanceTimersByTime(500);
|
||||
jest.advanceTimersByTime(500);
|
||||
|
||||
expect($.ajax).toHaveBeenCalledTimes(4);
|
||||
|
||||
});
|
||||
|
||||
describe("By default", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -175,17 +162,36 @@ describe('Update content', () => {
|
||||
|
||||
});
|
||||
|
||||
test("It should request updates every 1.5 seconds", () => {
|
||||
test("It should request updates with a dynamic interval", () => {
|
||||
|
||||
// First call happens straight away
|
||||
expect($.ajax).toHaveBeenCalledTimes(1);
|
||||
|
||||
// units are milliseconds
|
||||
jest.advanceTimersByTime(1500);
|
||||
// It took the server 1000ms to respond to the first call so we
|
||||
// will back off – the next call shouldn’t happen in the next 6904ms
|
||||
jest.advanceTimersByTime(6904);
|
||||
expect($.ajax).toHaveBeenCalledTimes(1);
|
||||
|
||||
// But it should happen after 6905ms
|
||||
jest.advanceTimersByTime(1);
|
||||
expect($.ajax).toHaveBeenCalledTimes(2);
|
||||
|
||||
});
|
||||
|
||||
each([
|
||||
[1000, 0],
|
||||
[1500, 100],
|
||||
[4590, 500],
|
||||
[6905, 1000],
|
||||
[24000, 10000],
|
||||
]).test('It calculates a delay of %dms if the API responds in %dms', (waitTime, responseTime) => {
|
||||
expect(
|
||||
window.GOVUK.Modules.UpdateContent.calculateBackoff(responseTime)
|
||||
).toBe(
|
||||
waitTime
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("If a form is used as a source for data, referenced in the data-form attribute", () => {
|
||||
|
||||
Reference in New Issue
Block a user