@@ -551,6 +551,90 @@ In a router application, you can define the ``put`` function that specifies how
551551
552552Learn more at :ref: `vshard-process-requests `.
553553
554+ .. _vshard-deduplication :
555+
556+ Deduplication of non-idempotent requests
557+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
558+
559+ **Idempotent requests ** produce the same result every time they are called.
560+ For example, a data read request or a multiplication by one are idempotent.
561+ Increment by one is an example of a non-idempotent operation.
562+ When such an operation is applied again, the value for the field will be increased by 2 instead of 1.
563+
564+ .. note ::
565+
566+ Any write requests that are planned to be executed repeatedly should be idempotent.
567+ The idempotency of such operations ensures that the change from the operation will be applied **only once **.
568+
569+ Re-invoking queries
570+
571+ A query may need to be re-executed if an error occurs on the server or client side.
572+ In this case:
573+
574+ - Read requests can be executed repeatedly. To do this, the method
575+ [vshard.router.call()](https://www.tarantool.io/ru/doc/latest/reference/reference_rock/vshard/vshard_router/#router-api-call)
576+ in the `read ` mode (`mode=read `) uses the `request_timeout ` parameter (available since `vshard ` 0.1.28).
577+ The `request_timeout ` and `timeout ` parameters must be passed together, observing the following condition:
578+
579+ For example, if ``timeout = 10 ``, and ``request_timeout = 2 ``,
580+ then within 10 seconds the router is able to make up to 5 attempts to contact (2 seconds each) with a request to different replicas,
581+ until the request finally succeeds.
582+
583+ - Write requests ([vshard.router.callrw()](https://www.tarantool.io/ru/doc/latest/reference/reference_rock/vshard/vshard_router/#router-api-callrw))
584+ in general **cannot be re-executed ** without checking that the request has not been applied before.
585+ Lack of such a check may lead to duplicate records or unplanned data changes.
586+
587+ For example, a client has sent a request to the server and is waiting for a response within a specified time.
588+ If the server sends a response about successful execution after this time has elapsed, the client will receive an error and when
589+ re-sending the request without additional checking, the operation may be applied twice.
590+
591+ A write request can be re-executed without a check only if the error occurred on the server side --
592+ for example, `ER_READONLY `.
593+
594+ Methods of deduplicating queries
595+
596+ To ensure idempotency of write queries, such as data insert, update, and upsert, as well as autoincrement,
597+ it is necessary to implement a check in the code that the query is being used for the first time.
598+
599+ For example, when adding a new tuple to a space, a unique key by which the insertion is performed can be used for checking.
600+ In such a query within a single transaction:
601+
602+ 1. It is checked whether there is a tuple with the key `key ` in the `bands ` space.
603+ 2. If there is no record with such a key in the space, the tuple is inserted.
604+
605+ .. code-block :: lua
606+
607+ box.begin()
608+ if box.space.bands:get{key} == nil then
609+ box.space.bands:insert{key, value}
610+ end
611+ box.commit()
612+
613+ For tuple update requests, a separate _deduplication_ space can be created, in which the query IDs will be saved.
614+ _deduplication_ space is a user space that contains a list of unique identifiers.
615+ Each such identifier corresponds to one executed query.
616+ This space can have any name, in the example it is called `deduplication `.
617+
618+ In the example below, within a single transaction:
619+
620+ 1. The `deduplication ` space is checked for the presence of the `deduplication_key ` request ID.
621+ 2. If there is no such ID, this ID is added to the deduplication space.
622+ 3. The request then increments the specified field in the `bands ` space by one.
623+
624+ This approach ensures that each data modification request will be executed **only once **.
625+
626+ .. code-block :: lua
627+
628+ function update_1(deduplication_key, key)
629+ box.begin()
630+ if box.space.deduplication:get{deduplication_key} == nil then
631+ box.space.deduplication:insert{deduplication_key}
632+ box.space.bands:update(key, {{'+', 'value', 1 }})
633+ end
634+ box.commit()
635+ end
636+
637+
554638 .. _vshard-maintenance :
555639
556640Sharded cluster maintenance
0 commit comments