mirror of https://github.com/zulip/zulip.git
api: Add zulip_version and zulip_feature_level in restart event.
This help mobile and terminal clients understand whether a server restart changed API feature levels or not, which in turn determines whether they will need to resynchronize their data. Also add tests and documentation for this previously undocumented event type. Fixes: #18205.
This commit is contained in:
parent
d2c18e28a4
commit
65c400e06d
|
@ -517,6 +517,8 @@ exports.fixtures = {
|
||||||
|
|
||||||
restart: {
|
restart: {
|
||||||
type: "restart",
|
type: "restart",
|
||||||
|
zulip_version: "4.0-dev+git",
|
||||||
|
zulip_feature_level: 55,
|
||||||
server_generation: 2,
|
server_generation: 2,
|
||||||
immediate: true,
|
immediate: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,11 @@ below features are supported.
|
||||||
|
|
||||||
## Changes in Zulip 4.0
|
## Changes in Zulip 4.0
|
||||||
|
|
||||||
|
**Feature level 59**
|
||||||
|
|
||||||
|
* [`GET /events`](/api/get-events): Added new `zulip_version` and
|
||||||
|
`zulip_feature_level` fields to the `restart` event.
|
||||||
|
|
||||||
**Feature level 58**
|
**Feature level 58**
|
||||||
|
|
||||||
* [`POST /register`](/api/register-queue): Added the new
|
* [`POST /register`](/api/register-queue): Added the new
|
||||||
|
|
|
@ -1142,7 +1142,13 @@ def check_realm_user_update(
|
||||||
|
|
||||||
|
|
||||||
restart_event = event_dict_type(
|
restart_event = event_dict_type(
|
||||||
required_keys=[("type", Equals("restart")), ("server_generation", int), ("immediate", bool)]
|
required_keys=[
|
||||||
|
("type", Equals("restart")),
|
||||||
|
("zulip_version", str),
|
||||||
|
("zulip_feature_level", int),
|
||||||
|
("server_generation", int),
|
||||||
|
("immediate", bool),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
check_restart_event = make_checker(restart_event)
|
check_restart_event = make_checker(restart_event)
|
||||||
|
|
||||||
|
|
|
@ -3114,6 +3114,68 @@ paths:
|
||||||
"realm_id": 2,
|
"realm_id": 2,
|
||||||
"id": 0,
|
"id": 0,
|
||||||
}
|
}
|
||||||
|
- type: object
|
||||||
|
description: |
|
||||||
|
Event sent to all the users whenever the Zulip server restarts.
|
||||||
|
|
||||||
|
Specifically, this event is sent whenever the Tornado process
|
||||||
|
for the user is restarted; in particular, this will always happen
|
||||||
|
when the Zulip server is upgraded.
|
||||||
|
|
||||||
|
Clients can use this event to know when they should get a new
|
||||||
|
event queue after a server upgrade. Clients doing so must implement
|
||||||
|
a random delay strategy to spread such restarts over 10 minutes or
|
||||||
|
more to avoid creating a synchronized thundering herd effect.
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
$ref: "#/components/schemas/EventIdSchema"
|
||||||
|
type:
|
||||||
|
allOf:
|
||||||
|
- $ref: "#/components/schemas/EventTypeSchema"
|
||||||
|
- enum:
|
||||||
|
- restart
|
||||||
|
zulip_version:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
The Zulip version number, in the format where this appears
|
||||||
|
in the [server_settings](/api/get-server-settings) and
|
||||||
|
[register](/api/register-queue) responses.
|
||||||
|
|
||||||
|
**Changes**: New in Zulip 4.0 (feature level 59).
|
||||||
|
zulip_feature_level:
|
||||||
|
type: integer
|
||||||
|
description: |
|
||||||
|
The [Zulip feature level](/api/changelog) of the server
|
||||||
|
after the restart.
|
||||||
|
|
||||||
|
Clients can safely avoid refetching their state and
|
||||||
|
creating a new event queue when the API feature level has not
|
||||||
|
changed, or when they know the specific feature level change
|
||||||
|
is not relevant to the client (E.g. it just adds a new endpoint
|
||||||
|
that the client doesn't use).
|
||||||
|
|
||||||
|
**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:
|
||||||
|
type: integer
|
||||||
|
description: |
|
||||||
|
The timestamp at which the server started.
|
||||||
|
additionalProperties: false
|
||||||
|
example:
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"immediate": True,
|
||||||
|
"server_generation": 1619334181,
|
||||||
|
"type": "restart",
|
||||||
|
"zulip_feature_level": 57,
|
||||||
|
"zulip_version": "4.0-dev+git",
|
||||||
|
}
|
||||||
- type: object
|
- type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
description: |
|
description: |
|
||||||
|
|
|
@ -6,6 +6,7 @@ import orjson
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
|
||||||
|
from version import API_FEATURE_LEVEL, ZULIP_VERSION
|
||||||
from zerver.lib.actions import check_send_message, do_change_user_role, do_set_realm_property
|
from zerver.lib.actions import check_send_message, do_change_user_role, do_set_realm_property
|
||||||
from zerver.lib.event_schema import check_restart_event
|
from zerver.lib.event_schema import check_restart_event
|
||||||
from zerver.lib.events import fetch_initial_state_data, get_raw_user_data
|
from zerver.lib.events import fetch_initial_state_data, get_raw_user_data
|
||||||
|
@ -877,6 +878,8 @@ class RestartEventsTest(ZulipTestCase):
|
||||||
restart_event,
|
restart_event,
|
||||||
dict(
|
dict(
|
||||||
type="restart",
|
type="restart",
|
||||||
|
zulip_version=ZULIP_VERSION,
|
||||||
|
zulip_feature_level=API_FEATURE_LEVEL,
|
||||||
server_generation=settings.SERVER_GENERATION,
|
server_generation=settings.SERVER_GENERATION,
|
||||||
immediate=True,
|
immediate=True,
|
||||||
id=0,
|
id=0,
|
||||||
|
|
|
@ -161,7 +161,12 @@ from zerver.lib.event_schema import (
|
||||||
check_user_group_update,
|
check_user_group_update,
|
||||||
check_user_status,
|
check_user_status,
|
||||||
)
|
)
|
||||||
from zerver.lib.events import apply_events, fetch_initial_state_data, post_process_state
|
from zerver.lib.events import (
|
||||||
|
RestartEventException,
|
||||||
|
apply_events,
|
||||||
|
fetch_initial_state_data,
|
||||||
|
post_process_state,
|
||||||
|
)
|
||||||
from zerver.lib.markdown import MentionData
|
from zerver.lib.markdown import MentionData
|
||||||
from zerver.lib.message import render_markdown
|
from zerver.lib.message import render_markdown
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
|
@ -198,6 +203,7 @@ from zerver.openapi.openapi import validate_against_openapi_schema
|
||||||
from zerver.tornado.event_queue import (
|
from zerver.tornado.event_queue import (
|
||||||
allocate_client_descriptor,
|
allocate_client_descriptor,
|
||||||
clear_client_event_queues_for_testing,
|
clear_client_event_queues_for_testing,
|
||||||
|
send_restart_events,
|
||||||
)
|
)
|
||||||
from zerver.views.realm_playgrounds import access_playground_by_id
|
from zerver.views.realm_playgrounds import access_playground_by_id
|
||||||
|
|
||||||
|
@ -1938,6 +1944,10 @@ 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:
|
||||||
|
with self.assertRaises(RestartEventException):
|
||||||
|
self.verify_action(lambda: send_restart_events(immediate=True))
|
||||||
|
|
||||||
|
|
||||||
class RealmPropertyActionTest(BaseAction):
|
class RealmPropertyActionTest(BaseAction):
|
||||||
def do_set_realm_property_test(self, name: str) -> None:
|
def do_set_realm_property_test(self, name: str) -> None:
|
||||||
|
|
|
@ -33,6 +33,7 @@ from django.conf import settings
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict
|
||||||
|
|
||||||
|
from version import API_FEATURE_LEVEL, ZULIP_VERSION
|
||||||
from zerver.decorator import cachify
|
from zerver.decorator import cachify
|
||||||
from zerver.lib.message import MessageDict
|
from zerver.lib.message import MessageDict
|
||||||
from zerver.lib.narrow import build_narrow_filter
|
from zerver.lib.narrow import build_narrow_filter
|
||||||
|
@ -572,7 +573,12 @@ def load_event_queues(port: int) -> None:
|
||||||
|
|
||||||
|
|
||||||
def send_restart_events(immediate: bool = False) -> None:
|
def send_restart_events(immediate: bool = False) -> None:
|
||||||
event: Dict[str, Any] = dict(type="restart", server_generation=settings.SERVER_GENERATION)
|
event: Dict[str, Any] = dict(
|
||||||
|
type="restart",
|
||||||
|
zulip_version=ZULIP_VERSION,
|
||||||
|
zulip_feature_level=API_FEATURE_LEVEL,
|
||||||
|
server_generation=settings.SERVER_GENERATION,
|
||||||
|
)
|
||||||
if immediate:
|
if immediate:
|
||||||
event["immediate"] = True
|
event["immediate"] = True
|
||||||
for client in clients.values():
|
for client in clients.values():
|
||||||
|
|
Loading…
Reference in New Issue