mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 13:33:24 +00:00
refactor: Extract watchdog module.
We now have 100% code coverage on this somewhat fiddly code. We also break activity's dependency on server_events.
This commit is contained in:
@@ -86,8 +86,8 @@ reload itself:
|
||||
garbage-collected by the server, meaning the browser can no longer
|
||||
get real-time updates altogether. In this case, the browser
|
||||
auto-reloads immediately in order to reconnect. We have coded an
|
||||
unsuspend trigger (based on some clever time logic) that ensures we
|
||||
check immediately when a client unsuspends; grep for `unsuspend` to
|
||||
unsuspend callback (based on some clever time logic) that ensures we
|
||||
check immediately when a client unsuspends; grep for `watchdog` to
|
||||
see the code.
|
||||
* If a new version of the server has been deployed, we want to reload
|
||||
the browser so that it will start running the latest code. However,
|
||||
|
||||
@@ -51,12 +51,12 @@ mock_esm("../../static/js/resize", {
|
||||
mock_esm("../../static/js/scroll_util", {
|
||||
scroll_element_into_container: () => {},
|
||||
});
|
||||
mock_esm("../../static/js/server_events", {
|
||||
check_for_unsuspend() {},
|
||||
});
|
||||
mock_esm("../../static/js/stream_popover", {
|
||||
show_streamlist_sidebar() {},
|
||||
});
|
||||
mock_esm("../../static/js/watchdog", {
|
||||
check_for_unsuspend() {},
|
||||
});
|
||||
set_global("document", _document);
|
||||
|
||||
const huddle_data = zrequire("huddle_data");
|
||||
|
||||
63
frontend_tests/node_tests/watchdog.js
Normal file
63
frontend_tests/node_tests/watchdog.js
Normal file
@@ -0,0 +1,63 @@
|
||||
"use strict";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
|
||||
const MockDate = require("mockdate");
|
||||
|
||||
const {set_global, zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
|
||||
let time = 0;
|
||||
let checker;
|
||||
MockDate.set(time);
|
||||
|
||||
function advance_secs(secs) {
|
||||
time += secs * 1000;
|
||||
MockDate.set(time);
|
||||
}
|
||||
|
||||
set_global("setInterval", (f, interval) => {
|
||||
checker = f;
|
||||
assert.equal(interval, 5000);
|
||||
});
|
||||
|
||||
const watchdog = zrequire("watchdog");
|
||||
|
||||
run_test("basics", () => {
|
||||
// Test without callbacks first.
|
||||
checker();
|
||||
advance_secs(5);
|
||||
checker();
|
||||
|
||||
let num_times_called_back = 0;
|
||||
|
||||
function callback() {
|
||||
num_times_called_back += 1;
|
||||
}
|
||||
|
||||
watchdog.on_unsuspend(callback);
|
||||
|
||||
// Simulate healthy operation.
|
||||
advance_secs(5);
|
||||
checker();
|
||||
assert.equal(num_times_called_back, 0);
|
||||
|
||||
// Simulate machine going to sleep.
|
||||
advance_secs(21);
|
||||
checker();
|
||||
assert.equal(num_times_called_back, 1);
|
||||
|
||||
// Simulate healthy operations resume, and
|
||||
// explicitly call check_for_unsuspend.
|
||||
num_times_called_back = 0;
|
||||
advance_secs(5);
|
||||
watchdog.check_for_unsuspend();
|
||||
assert.equal(num_times_called_back, 0);
|
||||
|
||||
// Simulate another suspension.
|
||||
advance_secs(21);
|
||||
watchdog.check_for_unsuspend();
|
||||
assert.equal(num_times_called_back, 1);
|
||||
});
|
||||
|
||||
MockDate.reset();
|
||||
@@ -12,9 +12,9 @@ import * as people from "./people";
|
||||
import * as pm_list from "./pm_list";
|
||||
import * as popovers from "./popovers";
|
||||
import * as presence from "./presence";
|
||||
import * as server_events from "./server_events";
|
||||
import {UserSearch} from "./user_search";
|
||||
import * as user_status from "./user_status";
|
||||
import * as watchdog from "./watchdog";
|
||||
|
||||
export let user_cursor;
|
||||
export let user_filter;
|
||||
@@ -195,7 +195,7 @@ export function send_presence_to_server(want_redraw) {
|
||||
return;
|
||||
}
|
||||
|
||||
server_events.check_for_unsuspend();
|
||||
watchdog.check_for_unsuspend();
|
||||
|
||||
channel.post({
|
||||
url: "/json/users/me/presence",
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as reload_state from "./reload_state";
|
||||
import * as sent_messages from "./sent_messages";
|
||||
import * as server_events_dispatch from "./server_events_dispatch";
|
||||
import * as ui_report from "./ui_report";
|
||||
import * as watchdog from "./watchdog";
|
||||
|
||||
// Docs: https://zulip.readthedocs.io/en/latest/subsystems/events-system.html
|
||||
|
||||
@@ -302,26 +303,8 @@ export function home_view_loaded() {
|
||||
$(document).trigger("home_view_loaded.zulip");
|
||||
}
|
||||
|
||||
let watchdog_time = Date.now();
|
||||
|
||||
export function check_for_unsuspend() {
|
||||
const new_time = Date.now();
|
||||
if (new_time - watchdog_time > 20000) {
|
||||
// 20 seconds.
|
||||
// Defensively reset watchdog_time here in case there's an
|
||||
// exception in one of the event handlers
|
||||
watchdog_time = new_time;
|
||||
// Our app's JS wasn't running, which probably means the machine was
|
||||
// asleep.
|
||||
$(document).trigger("unsuspend");
|
||||
}
|
||||
watchdog_time = new_time;
|
||||
}
|
||||
|
||||
setInterval(check_for_unsuspend, 5000);
|
||||
|
||||
export function initialize() {
|
||||
$(document).on("unsuspend", () => {
|
||||
watchdog.on_unsuspend(() => {
|
||||
// Immediately poll for new events on unsuspend
|
||||
blueslip.log("Restarting get_events due to unsuspend");
|
||||
get_events_failures = 0;
|
||||
|
||||
34
static/js/watchdog.js
Normal file
34
static/js/watchdog.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const unsuspend_callbacks = [];
|
||||
let watchdog_time = Date.now();
|
||||
|
||||
/*
|
||||
Our watchdog code checks every 5 seconds to make sure that we
|
||||
haven't gone 20 seconds since the last "5-second-ago" check.
|
||||
This sounds confusing, but it is just is a way to detect that
|
||||
the machine has gone to sleep.
|
||||
|
||||
When we detect the condition we call back to server_events code
|
||||
to reset ourselves accordingly.
|
||||
*/
|
||||
|
||||
export function check_for_unsuspend() {
|
||||
const new_time = Date.now();
|
||||
if (new_time - watchdog_time > 20000) {
|
||||
// 20 seconds.
|
||||
// Defensively reset watchdog_time here in case there's an
|
||||
// exception in one of the event handlers
|
||||
watchdog_time = new_time;
|
||||
// Our app's JS wasn't running, which probably means the machine was
|
||||
// asleep.
|
||||
for (const callback of unsuspend_callbacks) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
watchdog_time = new_time;
|
||||
}
|
||||
|
||||
export function on_unsuspend(f) {
|
||||
unsuspend_callbacks.push(f);
|
||||
}
|
||||
|
||||
setInterval(check_for_unsuspend, 5000);
|
||||
Reference in New Issue
Block a user