Skip to content

Document the watchers and built-in events #2858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 5, 2022
Next Next commit
Add new functions to module box
  • Loading branch information
xuniq committed Jul 29, 2022
commit ba2a698240a84062ce87b3a06bbbc5908d0a50b4
1 change: 1 addition & 0 deletions doc/reference/reference_lua/box.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ with ``box``, with no arguments. The ``box`` module contains:
box_space
box_stat
box_tuple
box_watchers

box_txn_management
box_sql
Expand Down
59 changes: 59 additions & 0 deletions doc/reference/reference_lua/box_watchers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.. _box-watchers:

--------------------------------------------------------------------------------
Functions for watchers
--------------------------------------------------------------------------------

The ``box`` module contains some functions related to the event subscriptions, also known as watchers.
The subscriptions are used to inform a client about server-side events.
To see the list of the built-in events in Tarantool,
check the :doc:`pub/sub <reference/reference_rock/vshard/vshard_pub-sub>` section.

.. glossary::

Watcher
A watcher is a :doc:`callback <doc/book/box/triggers>` invoked on a state change.
To create a local watcher, use the ``box.watch()`` function.

State
A state is a key-value pair stored internally.
The key is a string.
The value is any type that could be encoded as MsgPack.
To update a state, use the ``box.broadcast()`` function.

A watcher callback is passed the key for which it was registered and the current key data.
A watcher callback is always invoked in a new fiber, so it's okay to yield in it.
A watcher callback is never executed in parallel with itself:
if the key updates while the callback is running,
the callback will be invoked with the new value as soon as it returns.

The watch() function returns a watcher handle, which can be used to unregister the watcher
if it is not needed anymore by calling ``w:unregister()``.

Below is a list of all functions and members.

.. container:: table

.. rst-class:: left-align-column-1
.. rst-class:: left-align-column-2

.. list-table::
:widths: 25 75
:header-rows: 1

* - Name
- Use

* - :doc:`./box_watchers/watch`
- Create a local watcher.
To create a remote watcher, see the :ref:`conn:watch() <conn-watch>` function
in the ``net.box`` module.

* - :doc:`./box_watchers/broadcast`
- Update a state.

.. toctree::
:hidden:

box_watchers/watch
box_watchers/broadcast
15 changes: 15 additions & 0 deletions doc/reference/reference_lua/box_watchers/broadcast.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.. _box-broadcast:

================================================================================
box.broadcast()
================================================================================

.. function:: box.broadcast(key, value)

//Description

:param string key: a key name to subscribe to
:param ?mgspack value:

:return:
:rtype: ?
15 changes: 15 additions & 0 deletions doc/reference/reference_lua/box_watchers/watch.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.. _box-watch:

================================================================================
box.watch()
================================================================================

.. function:: box.watch(key, func)

Subscribe to events broadcast by a remote host.

:param string key: a key name to subscribe to
:param function func: a callback to invoke when the key value is updated

:return: a watcher handle that can be used to unregister the watcher
:rtype: ?
42 changes: 40 additions & 2 deletions doc/reference/reference_lua/net_box.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,16 @@ Below is a list of all ``net.box`` functions.
* - :ref:`conn:call() <net_box-call>`
- Call a stored procedure
* - :ref:`conn:timeout() <conn-timeout>`
- Set a timeout
- Set a timeout
* - :ref:`conn:watch() <conn-watch>`
- Subscribe to events broadcast by a remote host
* - :ref:`conn:on_connect() <net_box-on_connect>`
- Define a connect trigger
* - :ref:`conn:on_disconnect() <net_box-on_disconnect>`
- Define a disconnect trigger
* - :ref:`conn:on_schema_reload() <net_box-on_schema_reload>`
- Define a trigger when schema is modified
* - :ref:`conn:new_stream() <conn-new_stream>`
* - :ref:`conn:new_stream() <conn-new_stream>`
- Create a stream
* - :ref:`stream:begin() <net_box-stream_begin>`
- Begin a stream transaction
Expand Down Expand Up @@ -533,7 +535,43 @@ Below is a list of all ``net.box`` functions.
- B
...

.. _conn-watch:

.. method:: watch(key, func)

Subscribe to events broadcast by a remote host.

:param string key: a key name to subscribe to
:param function func: a callback to invoke when the key value is updated
:return: a watcher handle that can be used to unregister the watcher
:rtype: ?

.. admonition:: note

Garbage collection of a watcher handle doesn't result in unregistering the watcher.
It is okay to discard the result of box.watch if the watcher is never going to be unregistered.

**Example:**

Server:

.. code-block:: lua

-- Broadcast value 123 for key 'foo'.
box.broadcast('foo', 123)

Client:

.. code-block:: lua

conn = net.box.connect(URI)
-- Subscribe to updates of key 'foo'.
w = conn:watch('foo', function(key, value)
assert(key == 'foo')
-- do something with value
end)
-- Unregister the watcher when it's no longer needed.
w:unregister()

.. _conn-timeout:

Expand Down
19 changes: 10 additions & 9 deletions doc/reference/reference_rock/vshard/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ scaling in Tarantool.
Check out the :ref:`Quick start guide <vshard-quick-start>` -- or dive into the
complete ``vshard`` documentation:

.. toctree::
:maxdepth: 2
:numbered: 0
.. toctree::
:maxdepth: 2
:numbered: 0

vshard_summary_index
vshard_architecture
vshard_admin
vshard_quick
vshard_ref
vshard_api
vshard_summary_index
vshard_architecture
vshard_admin
vshard_quick
vshard_ref
vshard_api
vshard_pub-sub
135 changes: 135 additions & 0 deletions doc/reference/reference_rock/vshard/vshard_pub-sub.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
.. _vshard-pubsub:

Pub/sub system and its events
=============================

Pub/sub is a notification system for Tarantool events.
It is related to one-time subscriptions.

Events that the system will process:

box.id
box.status
box.election
box.schema

As a reaction to each event, the server sends back specific IPROTO fields.

Built-in events for pub/sub
---------------------------

The important purpose of the built-in events is to learn who is the
master, unless it is defined in an application specific way. Knowing who
is the master is necessary to send changes to a correct instance, and
probably make reads of the most actual data if it is important. Also
defined more built-in events for other mutable properties like leader
state change, his election role and election term, schema version change
and instance state.

Built-in events have a special naming schema --ё their name always starts
with box.. The prefix is reserved for built-in events. Creating new events
with this prefix is banned. Below is a list of all the events + their names
and values:

.. container:: table

.. list-table::
:widths: 20 40 40

* - Built-in event
- Description
- Value

* - box.id
- Identification of the instance. Changes are extra rare. Some
values never change or change only once. For example, instance UUID never
changes after the first box.cfg. But is not known before box.cfg is called.
Replicaset UUID is unknown until the instance joins to a replicaset or
bootsa new one, but the events are supposed to start working before that -
right at listen launch. Instance numeric ID is known only after
registration. On anonymous replicas is 0 until they are registered officially.
- .. code-block:: lua

{
MP_STR “id”: MP_UINT; box.info.id,
MP_STR “instance_uuid”: MP_UUID; box.info.uuid,
MP_STR “replicaset_uuid”: MP_UUID box.info.cluster.uuid,
}

* - box.status
- Generic blob about instance status. It is most commonly used
and not frequently changed config options and box.info fields.]
- .. code-block:: lua

{
MP_STR “is_ro”: MP_BOOL box.info.ro,
MP_STR “is_ro_cfg”: MP_BOOL box.cfg.read_only,
MP_STR “status”: MP_STR box.info.status,
}

* - box.election
- All the needed parts of box.info.election needed to find who is the most recent writable leader.
- .. code-block:: lua

{
MP_STR “term”: MP_UINT box.info.election.term,
MP_STR “role”: MP_STR box.info.election.state,
MP_STR “is_ro”: MP_BOOL box.info.ro,
MP_STR “leader”: MP_UINT box.info.election.leader,
}

* - box.schema
- Schema-related data. Currently it is only version.
- .. code-block:: lua

{
MP_STR “version”: MP_UINT schema_version,
}

Built-in events can't be override. Meaning, users can't be able to call
box.broadcast(‘box.id’, any_data) etc.

The events are available from the very beginning as not MP_NIL. It's
necessary for supported local subscriptions. Otherwise, there is no way to detect
whether an event is even supported at all by this Tarantool version. If
events are broadcast before box.cfg{}, then the following values will
available:
box.id = {}
box.schema = {}
box.status = {}
box.election = {}

This way, the users will be able to distinguish an event being not supported
at all from ``box.cfg{}`` being not called yet. Otherwise they would need to
parse ``_TARANTOOL`` version string locally and peer_version in net.box.

Usage example
-------------

.. code-block:: lua

conn = net.box.connect(URI)
-- Subscribe to updates of key 'box.id'
w = conn:watch('box.id', function(key, value)
assert(key == 'box.id')
-- do something with value
end)
-- or to updates of key 'box.status'
w = conn:watch('box.status', function(key, value)
assert(key == 'box.status')
-- do something with value
end)
-- or to updates of key 'box.election'
w = conn:watch('box.election', function(key, value)
assert(key == 'box.election')
-- do something with value
end)
-- or to updates of key 'box.schema'
w = conn:watch('box.schema', function(key, value)
assert(key == 'box.schema')
-- do something with value
end)
-- Unregister the watcher when it's no longer needed.
w:unregister()