Skip to content
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

Document the watchers and built-in events #2858

Merged
merged 13 commits into from
Aug 5, 2022
1 change: 1 addition & 0 deletions doc/reference/reference_lua/box.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ with ``box``, with no arguments. The ``box`` module contains:

box_txn_management
box_sql
box_events
box_once
box_snapshot

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

Event watchers
==============

The ``box`` module contains some features related to event subscriptions, also known as :term:`watchers <watcher>`.
The subscriptions are used to inform the client about server-side :term:`events <event>`.
Each event subscription is defined by a certain key.

.. glossary::

Event

An event is a state change or a system update that triggers the action of other systems.
To read more about built-in events in Tarantool,
check the :doc:`system events </reference/reference_lua/box_events/system_events>` section.

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

Watcher
A watcher is a :doc:`callback </book/box/triggers>` that is invoked when a state change occurs.
To register a local watcher, use the ``box.watch()`` function.
To create a remote watcher, use the ``watch()`` function from the ``net.box`` module.
Note that it is possible to register more than one watcher for the same key.

How the watcher works
---------------------
patiencedaur marked this conversation as resolved.
Show resolved Hide resolved

First, you register a watcher.
After that, the watcher callback is invoked for the first time.
In this case, the callback is triggered whether or not the key has already been broadcast.
All subsequent invocations are triggered with :doc:`box.broadcast() </reference/reference_lua/box_events/broadcast>`
called on the remote host.
If a watcher is subscribed for a key that has not been broadcast yet, the callback is triggered only once,
after the registration of the watcher.

The watcher callback takes two arguments.
The first argument is the name of the key for which it was registered.
The second one contains current key data.
The callback is always invoked in a new fiber. It means that it is allowed to yield in it.
A watcher callback is never executed in parallel with itself.
If the key is updated while the watcher callback is running, the callback will be invoked again with the new
value as soon as it returns.

``box.watch`` and ``box.broadcast`` functions can be used before :doc:`box.cfg </reference/reference_lua/box_cfg>`.

Below is a list of all functions and pages related to watchers or events.

.. 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_events/watch`
- Create a local watcher.

* - :ref:`conn:watch() <conn-watch>`
- Create a watcher for the remote host.

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

* - :ref:`Built-in events <system-events>`
- Predefined events in Tarantool

.. toctree::
:hidden:

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

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

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

Update the value of a particular key and notify all key watchers of the update.

:param string key: key name of the event to subscribe to
:param value: any data that can be encoded in MsgPack

:return: none

**Possible errors:**

* The value can't be encoded as MsgPack.
* The key refers to a ``box.`` system event

**Example:**

.. code-block:: lua

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


121 changes: 121 additions & 0 deletions doc/reference/reference_lua/box_events/system_events.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
.. _system-events:

System events
=============

Predefined events have a special naming schema -- theirs names always start with the reserved ``box.`` prefix.
It means that you cannot create new events with it.

The system processes the following events:

* ``box.id``
* ``box.status``
* ``box.election``
* ``box.schema``

In response to each event, the server sends back certain ``IPROTO`` fields.

The events are available from the beginning as non-:ref:`MP_NIL <box_protocol-notation>`.
If a watcher subscribes to a system event before it has been broadcast,
it receives an empty table for the event value.

The event is generated when there is a change in any of the values listed in the event.
For example, see the parameters in the ``box.id`` event below -- ``id``, ``instance_uuid``, and ``replicaset_uuid``.
Suppose the ``ìd`` value (``box.info.id``) has changed.
This triggers the ``box.info`` event, which states that the value of ``box.info.id`` has changed,
while ``box.info.uuid`` and ``box.info.cluster.uuid`` remain the same.

box.id
~~~~~~

Contains :ref:`identification <box_info_info>` of the instance.
Value changes are rare.

* ``id``: the numeric instance ID is unknown before the registration.
For anonymous replicas, the value is ``0`` until they are officially registered.

* ``instance_uuid``: the UUID of the instance never changes after the first
:doc:`box.cfg </reference/reference_lua/box_cfg>`.
The value is unknown before the ``box.cfg`` call.

* ``replicaset_uuid``: the value is unknown until the instance joins a replicaset or boots a new one.

.. code-block:: lua
patiencedaur marked this conversation as resolved.
Show resolved Hide resolved

-- box.id value
{
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
~~~~~~~~~~

Contains generic information about the instance status.

* ``is_ro``: :ref:`indicates the read-only mode <box_introspection-box_info>` or the ``orphan`` status.
* ``is_ro_cfg``: indicates the :ref:`read_only <cfg_basic-read_only>` mode for the instance.
* ``status``: shows the status of an instance.

.. code-block:: lua
patiencedaur marked this conversation as resolved.
Show resolved Hide resolved

{
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
~~~~~~~~~~~~

Contains fields of :doc:`box.info.election </reference/reference_lua/box_info/election>`
that are necessary to find out the most recent writable leader.

* ``term``: shows the current election term.
* ``role``: indicates the election state of the node -- ``leader``, ``follower``, or ``candidate``.
* ``is_ro``: :ref:`indicates the read-only mode <box_introspection-box_info>` or the ``orphan`` status.
* ``leader``: shows the leader node ID in the current term.

.. code-block:: lua
patiencedaur marked this conversation as resolved.
Show resolved Hide resolved

{
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
~~~~~~~~~~

Contains schema-related data.

* ``version``: shows the schema version.

.. code-block:: lua
patiencedaur marked this conversation as resolved.
Show resolved Hide resolved

{
MP_STR “version”: MP_UINT schema_version,
}

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

.. code-block:: lua

local conn = net.box.connect(URI)
local log = require('log')
-- Subscribe to updates of key 'box.id'
local w = conn:watch('box.id', function(key, value)
assert(key == 'box.id')
log.info("The box.id value is '%s'", value)
end)

If you want to unregister the watcher when it's no longer needed, use the following command:

.. code-block:: lua

w:unregister()
xuniq marked this conversation as resolved.
Show resolved Hide resolved


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

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

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

Subscribe to events broadcast by a local host.

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

:return: a watcher handle. The handle consists of one method -- ``unregister()``, which unregisters the watcher.

To read more about watchers, see the :ref:`Functions for watchers <box-watchers>` section.

.. note::

Keep in mind that garbage collection of a watcher handle doesn't lead to the watcher's destruction.
In this case, the watcher remains registered.
It is okay to discard the result of ``watch`` function if the watcher will never be unregistered.

**Example:**

Server:

.. code-block:: lua

xuniq marked this conversation as resolved.
Show resolved Hide resolved
-- Broadcast value 42 for the 'foo' key.
box.broadcast('foo', 42)

Client:

.. code-block:: lua

conn = require('net.box').connect(URI)
local log = require('log')
-- Subscribe to updates of the 'foo' key.
local w = box.watch('foo', function(key, value)
assert(key == 'foo')
log.info("The box.id value is '%d'", value)
end)

If you don't need the watcher anymore, you can unregister it using the command below:

.. code-block:: lua

w:unregister()

66 changes: 61 additions & 5 deletions doc/reference/reference_lua/net_box.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.. _net_box-module:
zc.. _net_box-module:

--------------------------------------------------------------------------------
Module net.box
Expand Down 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 @@ -216,7 +218,7 @@ Below is a list of all ``net.box`` functions.
support the specified features, the connection will fail with an error message.
With ``required_protocol_features = {'transactions'}``, all connections fail where the
server has ``transactions: false``.

.. container:: table

.. list-table::
Expand All @@ -240,7 +242,7 @@ Below is a list of all ``net.box`` functions.
- IPROTO_FEATURE_ERROR_EXTENSION
- 2 and newer
* - ``watchers``
- Requires remote watchers support on the server
- Requires remote :ref:`watchers <conn-watch>` support on the server
- IPROTO_FEATURE_WATCHERS
- 3 and newer

Expand Down Expand Up @@ -533,7 +535,61 @@ 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 of an event to subscribe to
:param function func: a callback to invoke when the key value is updated
:return: a watcher handle. The handle consists of one method -- ``unregister()``, which unregisters the watcher.

To read more about watchers, see the :ref:`Functions for watchers <box-watchers>` section.

The method has the same syntax as the :doc:`box.watch() </reference/reference_lua/box_events/broadcast>`
function, which is used for subscribing to events locally.

Watchers survive reconnection (see the ``reconnect_after`` connection :ref:`option <net_box-new>`).
All registered watchers are automatically resubscribed when the
connection is reestablished.

If a remote host supports watchers, the ``watchers`` key will be set in the
connection ``peer_protocol_features``.
For details, check the :ref:`net.box features table <net_box-new>`.

.. note::

Keep in mind that garbage collection of a watcher handle doesn't lead to the watcher's destruction.
In this case, the watcher remains registered.
It is okay to discard the result of ``watch`` function if the watcher will never be unregistered.

**Example:**

Server:
xuniq marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: lua

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

Client:

.. code-block:: lua

conn = net.box.connect(URI)
local log = require('log')
-- Subscribe to updates of the 'foo' key.
w = conn:watch('foo', function(key, value)
assert(key == 'foo')
log.info("The box.id value is '%d'", value)
end)

If you don't need the watcher anymore, you can unregister it using the command below:

.. code-block:: lua

w:unregister()

.. _conn-timeout:

Expand Down