|
9 | 9 | ===============================================================================
|
10 | 10 |
|
11 | 11 | The ``box.session`` submodule allows querying the session state, writing to a
|
12 |
| -session-specific temporary Lua table, or setting up triggers which will fire |
| 12 | +session-specific temporary Lua table, or sending out-of-band messages, or |
| 13 | +setting up triggers which will fire |
13 | 14 | when a session starts or ends. A *session* is an object associated with each
|
14 | 15 | client connection.
|
15 | 16 |
|
@@ -66,6 +67,10 @@ Below is a list of all ``box.session`` functions and members.
|
66 | 67 | | :ref:`box.session.on_auth() | Define an authentication |
|
67 | 68 | | <box_session-on_auth>` | trigger |
|
68 | 69 | +--------------------------------------+---------------------------------+
|
| 70 | + | :ref:`box.session.push() | Send an out-of-band message | |
| 71 | + | <box_session-push>` | | |
| 72 | + +--------------------------------------+---------------------------------+ |
| 73 | + |
69 | 74 |
|
70 | 75 | .. module:: box.session
|
71 | 76 |
|
@@ -476,3 +481,130 @@ Below is a list of all ``box.session`` functions and members.
|
476 | 481 | function 2, box.session.user()=guest
|
477 | 482 | function 2, user_name=admin
|
478 | 483 | function 1, box.session.user()=guest
|
| 484 | +
|
| 485 | +.. _box_session-push: |
| 486 | + |
| 487 | +.. function:: box.session.push(message [, sync]) |
| 488 | + |
| 489 | + Generate an out-of-band message. By "out-of-band" we mean an extra |
| 490 | + message which supplements what is passed in a network via the usual |
| 491 | + channels. Although ``box.session.push()`` can be called at any time, in |
| 492 | + practice it is used with networks that are set up with |
| 493 | + :ref:`module net.box <net_box-module>`, and |
| 494 | + it is invoked by the server (on the "remote database system" to use |
| 495 | + our terminology for net.box), and the client has options for getting |
| 496 | + such messages. |
| 497 | + |
| 498 | + :param string-or-number message: what to send |
| 499 | + :param int sync: for an optional argument to indicate what the session is, |
| 500 | + as taken from an earlier call to :ref:`box_session:sync() <box_session-sync>`. |
| 501 | + If it is omitted, the default is the current ``box.session.sync()`` value. |
| 502 | + :rtype: {nil, error} or true. |
| 503 | + |
| 504 | + If the result is an error, then the first part of the return is |
| 505 | + ``nil`` and the second part is the error object. If the result is not |
| 506 | + an error, then the return is the boolean value ``true``. |
| 507 | + When the return is ``true``, the message has gone to the network |
| 508 | + buffer as a :ref:`packet <box_protocol-iproto_protocol>` |
| 509 | + with the code IPROTO_CHUNK (0x80). |
| 510 | + |
| 511 | + The server's sole job is to call ``box.session.push()``, there is no |
| 512 | + automatic mechanism for showing that the message was received. |
| 513 | + The client's job is to check for such messages after it sends |
| 514 | + something to the server. The major client methods -- |
| 515 | + :ref:`conn:call <net_box-call>`, :ref:`conn:eval <net_box-eval>`, |
| 516 | + :ref:`conn:select <conn-select>`, :ref:`conn:insert <conn-insert>`, |
| 517 | + :ref:`conn:replace <conn-replace>`, :ref:`conn:update <conn-update>`, |
| 518 | + :ref:`conn:upsert <conn-upsert>`, :ref:`delete <conn-delete>` -- |
| 519 | + may cause the server to send a message. |
| 520 | + |
| 521 | + Situation 1: when the client calls synchronously with the default |
| 522 | + ``{async=false}`` option: there are two optional additional options: |
| 523 | + :samp:`on_push={function-name}`, and :samp:`on_push_ctx={function-argument}`. |
| 524 | + When the client receives an out-of-band message for the session, |
| 525 | + it invokes "function-name(function-argument)". For example, with |
| 526 | + options ``{on_push=table.insert, on_push_ctx=messages}``, the client |
| 527 | + will insert whatever it receives into a table named messages. |
| 528 | + |
| 529 | + Situation 2: when the client calls asynchronously with the non-default |
| 530 | + ``{async=true}`` option: ``on_push`` and ``on_push_ctx`` are not allowed, but |
| 531 | + the messages can be seen by calling ``pairs()`` in a loop. |
| 532 | + |
| 533 | + Situation 2 complication: ``pairs()`` is subject to timeout. So there |
| 534 | + is an optional argument = timeout per iteration. If timeout occurs before |
| 535 | + there is a new message or a final response, there is an error return. |
| 536 | + To check for an error a one can use the first loop parameter (if the loop |
| 537 | + starts with "for i, message in future:pairs()" then the first loop parameter |
| 538 | + is i). If it is box.NULL then the second parameter (in our example, "message") |
| 539 | + is the error object. |
| 540 | + |
| 541 | + ** Example ** |
| 542 | + |
| 543 | + .. code-block:: lua |
| 544 | +
|
| 545 | + -- Make two shells. On Shell#1 set up a "server", and |
| 546 | + -- in it have a function that includes box.session.push: |
| 547 | + box.cfg{listen=3301} |
| 548 | + box.schema.user.grant('guest','read,write,execute','universe') |
| 549 | + x = 0 |
| 550 | + fiber = require('fiber') |
| 551 | + function server_function() x=x+1; fiber.sleep(1); box.session.push(x); end |
| 552 | +
|
| 553 | + -- On Shell#2 connect to this server as a "client" that |
| 554 | + -- can handle Lua (such as another Tarantool server operating |
| 555 | + -- as a client), and initialize a table where we'll get messages: |
| 556 | + net_box = require('net.box') |
| 557 | + conn = net_box.connect(3301) |
| 558 | + messages_from_server = {} |
| 559 | +
|
| 560 | + -- On Shell#2 remotely call the server function and receive |
| 561 | + -- a SYNCHRONOUS out-of-band message: |
| 562 | + conn:call('server_function', {}, |
| 563 | + {is_async = false, |
| 564 | + on_push = table.insert, |
| 565 | + on_push_ctx = messages_from_server}) |
| 566 | + messages_from_server |
| 567 | + -- After a 1-second pause that is caused by the fiber.sleep() |
| 568 | + -- request inside server_function, the result in the |
| 569 | + -- messages_from_server table will be: 1. Like this: |
| 570 | + -- tarantool> messages_from_server |
| 571 | + -- --- |
| 572 | + -- - - 1 |
| 573 | + -- ... |
| 574 | + -- Good. That shows that box.session.push(x) worked, |
| 575 | + -- because we know that x was 1. |
| 576 | +
|
| 577 | + -- On Shell#2 remotely call the same server function and |
| 578 | + -- get an ASYNCHRONOUS out-of-band message. For this we cannot |
| 579 | + -- use on_push and on_push_ctx options, but we can use pairs(): |
| 580 | + future = conn:call('server_function', {}, {is_async = true}) |
| 581 | + messages = {} |
| 582 | + keys = {} |
| 583 | + for i, message in future:pairs() do |
| 584 | + table.insert(messages, message) table.insert(keys, i) end |
| 585 | + messages |
| 586 | + future:wait_result(1000) |
| 587 | + for i, message in future:pairs() do |
| 588 | + table.insert(messages, message) table.insert(keys, i) end |
| 589 | + messages |
| 590 | + -- There is no pause because conn:call does not wait for |
| 591 | + -- server_function to finish. The first time that we go through |
| 592 | + -- the pairs() loop, we see the messages table is empty. Like this: |
| 593 | + -- tarantool> messages |
| 594 | + -- --- |
| 595 | + -- - - 2 |
| 596 | + -- - [] |
| 597 | + -- ... |
| 598 | + -- That is okay because the server hasn't yet called |
| 599 | + -- box.session.push(). The second time that we go through |
| 600 | + -- the pairs() loop, we see the value of x at the time of |
| 601 | + -- the second call to box.session.push(). Like this: |
| 602 | + -- tarantool> messages |
| 603 | + -- --- |
| 604 | + -- - - 2 |
| 605 | + -- - &0 [] |
| 606 | + -- - 2 |
| 607 | + -- - *0 |
| 608 | + -- ... |
| 609 | + -- Good. That shows that the message was asynchronous, and |
| 610 | + -- that box.session.push() did its job. |
0 commit comments