mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	tornado: Split server restart events from web client reload events.
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						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(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user