@@ -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+ 
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+ 
554638vshard-maintenance :
555639
556640Sharded cluster maintenance
0 commit comments