mirror of https://github.com/zulip/zulip.git
tornado: Split server restart events from web client reload events.
This commit is contained in:
parent
a6287faea4
commit
fc41d6085b
|
@ -20,6 +20,14 @@ format used by the Zulip server that they are interacting with.
|
||||||
|
|
||||||
## Changes in Zulip 9.0
|
## Changes in Zulip 9.0
|
||||||
|
|
||||||
|
**Feature level 240**
|
||||||
|
|
||||||
|
* [`GET /events`](/api/get-events): The `restart` event no longer contains an
|
||||||
|
optional `immediate` flag.
|
||||||
|
* [`GET /events`](/api/get-events): A new `web_reload_client` event has been
|
||||||
|
added; it is used to signal to website-based clients that they should reload
|
||||||
|
their code. This was previously implied by the `restart` event.
|
||||||
|
|
||||||
Feature levels 238-239 are reserved for future use in 8.x maintenance
|
Feature levels 238-239 are reserved for future use in 8.x maintenance
|
||||||
releases.
|
releases.
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.9.3"
|
||||||
# Changes should be accompanied by documentation explaining what the
|
# Changes should be accompanied by documentation explaining what the
|
||||||
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
# new level means in api_docs/changelog.md, as well as "**Changes**"
|
||||||
# entries in the endpoint's documentation in `zulip.yaml`.
|
# entries in the endpoint's documentation in `zulip.yaml`.
|
||||||
API_FEATURE_LEVEL = 237
|
API_FEATURE_LEVEL = 240
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
# only when going from an old version of the code to a newer version. Bump
|
# only when going from an old version of the code to a newer version. Bump
|
||||||
|
|
|
@ -165,7 +165,12 @@ export function dispatch_normal_event(event) {
|
||||||
activity_ui.update_presence_info(event.user_id, event.presence, event.server_timestamp);
|
activity_ui.update_presence_info(event.user_id, event.presence, event.server_timestamp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "restart": {
|
case "restart":
|
||||||
|
realm.zulip_version = event.zulip_version;
|
||||||
|
realm.zulip_merge_base = event.zulip_merge_base;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "web_reload_client": {
|
||||||
const reload_options = {
|
const reload_options = {
|
||||||
save_pointer: true,
|
save_pointer: true,
|
||||||
save_narrow: true,
|
save_narrow: true,
|
||||||
|
|
|
@ -747,8 +747,15 @@ run_test("realm_user", ({override}) => {
|
||||||
assert.equal(removed_person.full_name, "translated: Unknown user");
|
assert.equal(removed_person.full_name, "translated: Unknown user");
|
||||||
});
|
});
|
||||||
|
|
||||||
run_test("restart", ({override}) => {
|
run_test("restart", ({_override}) => {
|
||||||
const event = event_fixtures.restart;
|
const event = event_fixtures.restart;
|
||||||
|
dispatch(event);
|
||||||
|
assert_same(realm.zulip_version, event.zulip_version);
|
||||||
|
assert_same(realm.zulip_merge_base, event.zulip_merge_base);
|
||||||
|
});
|
||||||
|
|
||||||
|
run_test("web_reload_client", ({override}) => {
|
||||||
|
const event = event_fixtures.web_reload_client;
|
||||||
const stub = make_stub();
|
const stub = make_stub();
|
||||||
override(reload, "initiate", stub.f);
|
override(reload, "initiate", stub.f);
|
||||||
dispatch(event);
|
dispatch(event);
|
||||||
|
|
|
@ -604,11 +604,10 @@ exports.fixtures = {
|
||||||
|
|
||||||
restart: {
|
restart: {
|
||||||
type: "restart",
|
type: "restart",
|
||||||
zulip_version: "4.0-dev+git",
|
zulip_version: "9.0-dev-753-gced3e85da9",
|
||||||
zulip_merge_base: "",
|
zulip_merge_base: "9.0-dev-743-g54053c1d28",
|
||||||
zulip_feature_level: 55,
|
zulip_feature_level: 237,
|
||||||
server_generation: 2,
|
server_generation: 1707511515,
|
||||||
immediate: true,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
scheduled_messages__add: {
|
scheduled_messages__add: {
|
||||||
|
@ -1084,4 +1083,9 @@ exports.fixtures = {
|
||||||
last_updated: fake_now,
|
last_updated: fake_now,
|
||||||
visibility_policy: 1,
|
visibility_policy: 1,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
web_reload_client: {
|
||||||
|
type: "web_reload_client",
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1253,11 +1253,18 @@ restart_event = event_dict_type(
|
||||||
("zulip_merge_base", str),
|
("zulip_merge_base", str),
|
||||||
("zulip_feature_level", int),
|
("zulip_feature_level", int),
|
||||||
("server_generation", int),
|
("server_generation", int),
|
||||||
("immediate", bool),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
check_restart_event = make_checker(restart_event)
|
check_restart_event = make_checker(restart_event)
|
||||||
|
|
||||||
|
web_reload_client_event = event_dict_type(
|
||||||
|
required_keys=[
|
||||||
|
("type", Equals("web_reload_client")),
|
||||||
|
("immediate", bool),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
check_web_reload_client_event = make_checker(web_reload_client_event)
|
||||||
|
|
||||||
scheduled_message_fields = DictType(
|
scheduled_message_fields = DictType(
|
||||||
required_keys=[
|
required_keys=[
|
||||||
("scheduled_message_id", int),
|
("scheduled_message_id", int),
|
||||||
|
|
|
@ -91,9 +91,10 @@ from zerver.tornado.django_api import get_user_events, request_event_queue
|
||||||
from zproject.backends import email_auth_enabled, password_auth_enabled
|
from zproject.backends import email_auth_enabled, password_auth_enabled
|
||||||
|
|
||||||
|
|
||||||
class RestartEventError(Exception):
|
class WebReloadClientError(Exception):
|
||||||
"""
|
"""Special error for handling web_reload_client events in
|
||||||
Special error for handling restart events in apply_events.
|
apply_events.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -711,8 +712,8 @@ def apply_events(
|
||||||
user_list_incomplete: bool,
|
user_list_incomplete: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
for event in events:
|
for event in events:
|
||||||
if event["type"] == "restart":
|
if event["type"] == "web_reload_client":
|
||||||
raise RestartEventError
|
raise WebReloadClientError
|
||||||
if fetch_event_types is not None and event["type"] not in fetch_event_types:
|
if fetch_event_types is not None and event["type"] not in fetch_event_types:
|
||||||
# TODO: continuing here is not, most precisely, correct.
|
# TODO: continuing here is not, most precisely, correct.
|
||||||
# In theory, an event of one type, e.g. `realm_user`,
|
# In theory, an event of one type, e.g. `realm_user`,
|
||||||
|
@ -1652,7 +1653,7 @@ def do_events_register(
|
||||||
linkifier_url_template=linkifier_url_template,
|
linkifier_url_template=linkifier_url_template,
|
||||||
user_list_incomplete=user_list_incomplete,
|
user_list_incomplete=user_list_incomplete,
|
||||||
)
|
)
|
||||||
except RestartEventError:
|
except WebReloadClientError:
|
||||||
# This represents a rare race condition, where Tornado
|
# This represents a rare race condition, where Tornado
|
||||||
# restarted (and sent `restart` events) while we were waiting
|
# restarted (and sent `restart` events) while we were waiting
|
||||||
# for fetch_initial_state_data to return. To avoid the client
|
# for fetch_initial_state_data to return. To avoid the client
|
||||||
|
|
|
@ -4000,10 +4000,15 @@ paths:
|
||||||
for the user is restarted; in particular, this will always happen
|
for the user is restarted; in particular, this will always happen
|
||||||
when the Zulip server is upgraded.
|
when the Zulip server is upgraded.
|
||||||
|
|
||||||
Clients can use this event to know when they should get a new
|
Clients should use this event to update their tracking of the
|
||||||
event queue after a server upgrade. Clients doing so must implement
|
server's capabilities, and to decide if they wish to get a new
|
||||||
a random delay strategy to spread such restarts over 10 minutes or
|
event queue after a server upgrade. Clients doing so must
|
||||||
more to avoid creating a synchronized thundering herd effect.
|
implement a random delay strategy to spread such restarts over 5
|
||||||
|
minutes or more to avoid creating a synchronized thundering herd
|
||||||
|
effect.
|
||||||
|
|
||||||
|
**Changes**: Removed the `immediate` flag, which was only used by
|
||||||
|
web clients in development, in Zulip 9.0 (feature level 240).
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/EventIdSchema"
|
$ref: "#/components/schemas/EventIdSchema"
|
||||||
|
@ -4034,20 +4039,15 @@ paths:
|
||||||
The [Zulip feature level](/api/changelog) of the server
|
The [Zulip feature level](/api/changelog) of the server
|
||||||
after the restart.
|
after the restart.
|
||||||
|
|
||||||
Clients can safely avoid refetching their state and
|
Clients should use this to update their tracking of the
|
||||||
creating a new event queue when the API feature level has not
|
server's capabilities, and may choose to refetch their state
|
||||||
changed, or when they know the specific feature level change
|
and create a new event queue when the API feature level has
|
||||||
is not relevant to the client (E.g. it just adds a new endpoint
|
changed in a way that the client finds significant. Clients
|
||||||
that the client doesn't use).
|
choosing to do so must implement a random delay strategy to
|
||||||
|
spread such restarts over 5 or more minutes to avoid creating
|
||||||
|
a synchronized thundering herd effect.
|
||||||
|
|
||||||
**Changes**: New in Zulip 4.0 (feature level 59).
|
**Changes**: New in Zulip 4.0 (feature level 59).
|
||||||
immediate:
|
|
||||||
type: boolean
|
|
||||||
description: |
|
|
||||||
Whether the client should fetch a new event queue immediately,
|
|
||||||
rather than using a backoff strategy to avoid thundering herds.
|
|
||||||
A Zulip development server uses this parameter to reload
|
|
||||||
clients immediately.
|
|
||||||
server_generation:
|
server_generation:
|
||||||
type: integer
|
type: integer
|
||||||
description: |
|
description: |
|
||||||
|
@ -4056,13 +4056,47 @@ paths:
|
||||||
example:
|
example:
|
||||||
{
|
{
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"immediate": true,
|
|
||||||
"server_generation": 1619334181,
|
"server_generation": 1619334181,
|
||||||
"type": "restart",
|
"type": "restart",
|
||||||
"zulip_feature_level": 57,
|
"zulip_feature_level": 57,
|
||||||
"zulip_version": "5.0-dev-1650-gc3fd37755f",
|
"zulip_version": "5.0-dev-1650-gc3fd37755f",
|
||||||
"zulip_merge_base": "5.0-dev-1646-gea6b21cd8c",
|
"zulip_merge_base": "5.0-dev-1646-gea6b21cd8c",
|
||||||
}
|
}
|
||||||
|
- type: object
|
||||||
|
description: |
|
||||||
|
An event which signals the official Zulip web/desktop app to update,
|
||||||
|
by reloading the page and fetching a new queue; this will generally
|
||||||
|
follow a `restart` event. Clients which do not obtain their code
|
||||||
|
from the server (e.g. mobile and terminal clients, which store their
|
||||||
|
code locally) should ignore this event.
|
||||||
|
|
||||||
|
Clients choosing to reload the application must implement a random
|
||||||
|
delay strategy to spread such restarts over 5 or more minutes to
|
||||||
|
avoid creating a synchronized thundering herd effect.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 9.0 (feature level 240).
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
$ref: "#/components/schemas/EventIdSchema"
|
||||||
|
type:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/EventTypeSchema"
|
||||||
|
- enum:
|
||||||
|
- web_reload_client
|
||||||
|
immediate:
|
||||||
|
type: boolean
|
||||||
|
description: |
|
||||||
|
Whether the client should fetch a new event queue immediately,
|
||||||
|
rather than using a backoff strategy to avoid thundering herds.
|
||||||
|
A Zulip development server uses this parameter to reload
|
||||||
|
clients immediately.
|
||||||
|
additionalProperties: false
|
||||||
|
example:
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"type": "web_reload_client",
|
||||||
|
"immediate": true,
|
||||||
|
}
|
||||||
- type: object
|
- type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
description: |
|
description: |
|
||||||
|
|
|
@ -10,13 +10,12 @@ from django.test import override_settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
from version import API_FEATURE_LEVEL, ZULIP_MERGE_BASE, ZULIP_VERSION
|
|
||||||
from zerver.actions.custom_profile_fields import try_update_realm_custom_profile_field
|
from zerver.actions.custom_profile_fields import try_update_realm_custom_profile_field
|
||||||
from zerver.actions.message_send import check_send_message
|
from zerver.actions.message_send import check_send_message
|
||||||
from zerver.actions.presence import do_update_user_presence
|
from zerver.actions.presence import do_update_user_presence
|
||||||
from zerver.actions.user_settings import do_change_user_setting
|
from zerver.actions.user_settings import do_change_user_setting
|
||||||
from zerver.actions.users import do_change_user_role
|
from zerver.actions.users import do_change_user_role
|
||||||
from zerver.lib.event_schema import check_restart_event
|
from zerver.lib.event_schema import check_web_reload_client_event
|
||||||
from zerver.lib.events import fetch_initial_state_data
|
from zerver.lib.events import fetch_initial_state_data
|
||||||
from zerver.lib.exceptions import AccessDeniedError
|
from zerver.lib.exceptions import AccessDeniedError
|
||||||
from zerver.lib.request import RequestVariableMissingError
|
from zerver.lib.request import RequestVariableMissingError
|
||||||
|
@ -38,7 +37,7 @@ from zerver.tornado.event_queue import (
|
||||||
clear_client_event_queues_for_testing,
|
clear_client_event_queues_for_testing,
|
||||||
get_client_info_for_message_event,
|
get_client_info_for_message_event,
|
||||||
process_message_event,
|
process_message_event,
|
||||||
send_restart_events,
|
send_web_reload_client_events,
|
||||||
)
|
)
|
||||||
from zerver.tornado.exceptions import BadEventQueueIdError
|
from zerver.tornado.exceptions import BadEventQueueIdError
|
||||||
from zerver.tornado.views import get_events, get_events_backend
|
from zerver.tornado.views import get_events, get_events_backend
|
||||||
|
@ -1100,7 +1099,7 @@ class ClientDescriptorsTest(ZulipTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RestartEventsTest(ZulipTestCase):
|
class WebReloadClientsTest(ZulipTestCase):
|
||||||
def tornado_call(
|
def tornado_call(
|
||||||
self,
|
self,
|
||||||
view_func: Callable[[HttpRequest, UserProfile], HttpResponse],
|
view_func: Callable[[HttpRequest, UserProfile], HttpResponse],
|
||||||
|
@ -1122,7 +1121,7 @@ class RestartEventsTest(ZulipTestCase):
|
||||||
)
|
)
|
||||||
return view_func(request, user_profile)
|
return view_func(request, user_profile)
|
||||||
|
|
||||||
def test_restart(self) -> None:
|
def test_web_reload_clients(self) -> None:
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
realm = hamlet.realm
|
realm = hamlet.realm
|
||||||
|
|
||||||
|
@ -1141,28 +1140,24 @@ class RestartEventsTest(ZulipTestCase):
|
||||||
)
|
)
|
||||||
client = allocate_client_descriptor(queue_data)
|
client = allocate_client_descriptor(queue_data)
|
||||||
|
|
||||||
send_restart_events(immediate=True)
|
send_web_reload_client_events()
|
||||||
|
|
||||||
self.assert_length(client.event_queue.queue, 1)
|
self.assert_length(client.event_queue.queue, 1)
|
||||||
restart_event = client.event_queue.queue[0]
|
reload_event = client.event_queue.queue[0]
|
||||||
|
|
||||||
check_restart_event("restart_event", restart_event)
|
check_web_reload_client_event("web_reload_client_event", reload_event)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
restart_event,
|
reload_event,
|
||||||
dict(
|
dict(
|
||||||
type="restart",
|
type="web_reload_client",
|
||||||
zulip_version=ZULIP_VERSION,
|
immediate=False,
|
||||||
zulip_merge_base=ZULIP_MERGE_BASE,
|
|
||||||
zulip_feature_level=API_FEATURE_LEVEL,
|
|
||||||
server_generation=settings.SERVER_GENERATION,
|
|
||||||
immediate=True,
|
|
||||||
id=0,
|
id=0,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_restart_event_recursive_call_logic(self) -> None:
|
def test_web_reload_client_event_recursive_call_logic(self) -> None:
|
||||||
# This is a test for a subtle corner case; see the comments
|
# This is a test for a subtle corner case; see the comments
|
||||||
# around RestartEventError for details.
|
# around WebReloadClientError for details.
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
realm = hamlet.realm
|
realm = hamlet.realm
|
||||||
|
|
||||||
|
@ -1182,16 +1177,16 @@ class RestartEventsTest(ZulipTestCase):
|
||||||
)
|
)
|
||||||
client = allocate_client_descriptor(queue_data)
|
client = allocate_client_descriptor(queue_data)
|
||||||
|
|
||||||
# Add a restart event to it.
|
# Add a reload event to it.
|
||||||
send_restart_events(immediate=True)
|
send_web_reload_client_events()
|
||||||
|
|
||||||
# Make a second queue after the restart events were sent.
|
# Make a second queue after the reload events were sent.
|
||||||
second_client = allocate_client_descriptor(queue_data)
|
second_client = allocate_client_descriptor(queue_data)
|
||||||
|
|
||||||
# Fetch the restart event just sent above, without removing it
|
# Fetch the reload event just sent above, without removing it
|
||||||
# from the queue. We will use this as a mock return value in
|
# from the queue. We will use this as a mock return value in
|
||||||
# get_user_events.
|
# get_user_events.
|
||||||
restart_event = orjson.loads(
|
reload_event = orjson.loads(
|
||||||
self.tornado_call(
|
self.tornado_call(
|
||||||
get_events_backend,
|
get_events_backend,
|
||||||
hamlet,
|
hamlet,
|
||||||
|
@ -1209,7 +1204,7 @@ class RestartEventsTest(ZulipTestCase):
|
||||||
|
|
||||||
# Now the tricky part: We call events_register_backend,
|
# Now the tricky part: We call events_register_backend,
|
||||||
# arranging it so that the first `get_user_events` call
|
# arranging it so that the first `get_user_events` call
|
||||||
# returns our restart event (triggering the recursive
|
# returns our reload event (triggering the recursive
|
||||||
# behavior), but the second (with a new queue) returns no
|
# behavior), but the second (with a new queue) returns no
|
||||||
# events.
|
# events.
|
||||||
#
|
#
|
||||||
|
@ -1219,7 +1214,7 @@ class RestartEventsTest(ZulipTestCase):
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
"zerver.lib.events.request_event_queue",
|
"zerver.lib.events.request_event_queue",
|
||||||
side_effect=[client.event_queue.id, second_client.event_queue.id],
|
side_effect=[client.event_queue.id, second_client.event_queue.id],
|
||||||
), mock.patch("zerver.lib.events.get_user_events", side_effect=[restart_event, []]):
|
), mock.patch("zerver.lib.events.get_user_events", side_effect=[reload_event, []]):
|
||||||
self.tornado_call(
|
self.tornado_call(
|
||||||
events_register_backend,
|
events_register_backend,
|
||||||
hamlet,
|
hamlet,
|
||||||
|
|
|
@ -201,7 +201,7 @@ from zerver.lib.event_schema import (
|
||||||
check_user_topic,
|
check_user_topic,
|
||||||
)
|
)
|
||||||
from zerver.lib.events import (
|
from zerver.lib.events import (
|
||||||
RestartEventError,
|
WebReloadClientError,
|
||||||
apply_events,
|
apply_events,
|
||||||
fetch_initial_state_data,
|
fetch_initial_state_data,
|
||||||
post_process_state,
|
post_process_state,
|
||||||
|
@ -251,7 +251,7 @@ from zerver.tornado.event_queue import (
|
||||||
allocate_client_descriptor,
|
allocate_client_descriptor,
|
||||||
clear_client_event_queues_for_testing,
|
clear_client_event_queues_for_testing,
|
||||||
create_heartbeat_event,
|
create_heartbeat_event,
|
||||||
send_restart_events,
|
send_web_reload_client_events,
|
||||||
)
|
)
|
||||||
from zerver.views.realm_playgrounds import access_playground_by_id
|
from zerver.views.realm_playgrounds import access_playground_by_id
|
||||||
|
|
||||||
|
@ -3456,9 +3456,9 @@ class NormalActionsTest(BaseAction):
|
||||||
events = self.verify_action(lambda: do_set_zoom_token(self.user_profile, None))
|
events = self.verify_action(lambda: do_set_zoom_token(self.user_profile, None))
|
||||||
check_has_zoom_token("events[0]", events[0], value=False)
|
check_has_zoom_token("events[0]", events[0], value=False)
|
||||||
|
|
||||||
def test_restart_event(self) -> None:
|
def test_web_reload_client_event(self) -> None:
|
||||||
with self.assertRaises(RestartEventError):
|
with self.assertRaises(WebReloadClientError):
|
||||||
self.verify_action(lambda: send_restart_events(immediate=True))
|
self.verify_action(lambda: send_web_reload_client_events())
|
||||||
|
|
||||||
def test_display_setting_event_not_sent(self) -> None:
|
def test_display_setting_event_not_sent(self) -> None:
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
|
|
|
@ -629,7 +629,7 @@ def load_event_queues(port: int) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def send_restart_events(immediate: bool = False) -> None:
|
def send_restart_events() -> None:
|
||||||
event: Dict[str, Any] = dict(
|
event: Dict[str, Any] = dict(
|
||||||
type="restart",
|
type="restart",
|
||||||
zulip_version=ZULIP_VERSION,
|
zulip_version=ZULIP_VERSION,
|
||||||
|
@ -637,8 +637,16 @@ def send_restart_events(immediate: bool = False) -> None:
|
||||||
zulip_feature_level=API_FEATURE_LEVEL,
|
zulip_feature_level=API_FEATURE_LEVEL,
|
||||||
server_generation=settings.SERVER_GENERATION,
|
server_generation=settings.SERVER_GENERATION,
|
||||||
)
|
)
|
||||||
if immediate:
|
for client in clients.values():
|
||||||
event["immediate"] = True
|
if client.accepts_event(event):
|
||||||
|
client.add_event(event)
|
||||||
|
|
||||||
|
|
||||||
|
def send_web_reload_client_events(immediate: bool = False) -> None:
|
||||||
|
event: Dict[str, Any] = dict(
|
||||||
|
type="web_reload_client",
|
||||||
|
immediate=immediate,
|
||||||
|
)
|
||||||
for client in clients.values():
|
for client in clients.values():
|
||||||
if client.accepts_event(event):
|
if client.accepts_event(event):
|
||||||
client.add_event(event)
|
client.add_event(event)
|
||||||
|
@ -656,7 +664,8 @@ async def setup_event_queue(server: tornado.httpserver.HTTPServer, port: int) ->
|
||||||
pc = tornado.ioloop.PeriodicCallback(lambda: gc_event_queues(port), EVENT_QUEUE_GC_FREQ_MSECS)
|
pc = tornado.ioloop.PeriodicCallback(lambda: gc_event_queues(port), EVENT_QUEUE_GC_FREQ_MSECS)
|
||||||
pc.start()
|
pc.start()
|
||||||
|
|
||||||
send_restart_events(immediate=settings.DEVELOPMENT)
|
send_restart_events()
|
||||||
|
send_web_reload_client_events(immediate=settings.DEVELOPMENT)
|
||||||
|
|
||||||
|
|
||||||
def fetch_events(
|
def fetch_events(
|
||||||
|
|
Loading…
Reference in New Issue