@@ -551,6 +551,93 @@ 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+ So, 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 are applied **only once **.
568+ 
569+ A request may need to be re-executed if an error occurs on the server or client side.
570+ In this case:
571+ 
572+ - Read requests can be executed repeatedly.
573+   To do this, the :ref: `vshard.router.call(mode=read)  <router_api-call >` uses the `request_timeout ` parameter
574+   (since `vshard ` 0.1.28).
575+   The `request_timeout ` and `timeout ` parameters should be passed together, observing the following condition:
576+ 
577+   ..  code-block :: text 
578+ 
579+       timeout > request_timeout 
580+ 
581+ 
582+ timeout = 10 `` and ``request_timeout = 2 ``,
583+   within 10 seconds the router is able to make up to 5 attempts to contact (2 seconds each) with a request to different replicas,
584+   until the request finally succeeds.
585+ 
586+ - Write requests (:ref: `vshard.router.callrw()  <router_api-callrw >`) generally **can't be re-executed ** without checking
587+   that the request has not been applied before.
588+   Lack of such a check may lead to duplicate records or unplanned data changes.
589+ 
590+   For example, a client has sent a request to the server, waiting for response within a specified timeout.
591+   If the server sends a response about successful execution after this time has elapsed, the client will receive an error.
592+   When re-executing the request without additional checking, the operation may be applied twice.
593+ 
594+   A write request can be re-executed without a check only if the error occurred on the server side --
595+   for example, `ER_READONLY `.
596+ 
597+ **Deduplication examples **
598+ 
599+ To ensure idempotency of write queries, such as data insert, update, and upsert, as well as autoincrement,
600+ it is necessary to implement a check in the code that the request is being used for the first time.
601+ 
602+ For example, when adding a new tuple to a space, a unique key by which the insertion is performed can be used for checking.
603+ In such a request within a single transaction:
604+ 
605+ 1. It is checked whether there is a tuple with the key `key ` in the `bands ` space.
606+ 2. If there is no record with such a key in the space, the tuple is inserted.
607+ 
608+ ..  code-block :: lua 
609+ 
610+     box.begin() 
611+     if box.space.bands:get{key} == nil then 
612+         box.space.bands:insert{key, value} 
613+     end 
614+     box.commit() 
615+ 
616+ deduplication * space can be created, in which the request IDs will be saved.
617+ *Deduplication space * is a user space that contains a list of unique identifiers.
618+ Each such identifier corresponds to one executed request.
619+ This space can have any name, in the example it is called ``deduplication ``.
620+ 
621+ In the example below, within a single transaction:
622+ 
623+ 1. The ``deduplication `` space is checked for the presence of the ``deduplication_key `` request ID.
624+ 2. If there is no such ID, this ID is added to the deduplication space.
625+ 3. The request then increments the specified field in the ``bands `` space by one.
626+ 
627+ This approach ensures that each data modification request will be executed **only once **.
628+ 
629+ ..  code-block :: lua 
630+ 
631+     function update_1(deduplication_key, key) 
632+         box.begin() 
633+         if box.space.deduplication:get{deduplication_key} == nil then 
634+             box.space.deduplication:insert{deduplication_key} 
635+             box.space.bands:update(key, {{'+', 'value', 1 }}) 
636+         end 
637+         box.commit() 
638+     end 
639+ 
640+ 
554641vshard-maintenance :
555642
556643Sharded cluster maintenance
0 commit comments