Skip to content

Latest commit

 

History

History
27 lines (22 loc) · 2.11 KB

RetryingTarantoolClient.md

File metadata and controls

27 lines (22 loc) · 2.11 KB

Main page

Retrying client

For the cases of reliable communication with a Cartridge cluster under heavy load or in a case of some failure causing unavailability of a part of the cluster nodes, the methods of client builder with prefix withRetrying may be useful.

The request retry policy allows specifying the types of exceptions that may be retried. By default, failed requests will be repeated only for some known network problems, such as TimeoutException, TarantoolConnectionException and TarantoolInternalNetworkException. Some retry policies are available in the TarantoolRequestRetryPolicies class, but you may use your own implementations. If you want to use proxy calls or retry settings only for a number of requests, you may use configureClient(client) in TarantoolClientFactory for making a new configured client instance. Note, that the new instance will share the same connection pool and basic client settings, and only augment the behavior of the client.

In this example I use custom delete function.

function delete_with_error_if_not_found(space_name, key, opts)
local result, err = crud.delete(space_name, key, opts)
if err then
return nil, err
end
if #result.rows == 0 then
return nil, "Records not found"
end
return result
end
You can set up any client. In this case I use CRUD client.
private TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> getCrudClient() {
return TarantoolClientFactory.createClient()
// You can connect to multiple routers
.withAddresses(
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3301)),
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3302)),
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3303))
)
// For connecting to a Cartridge application,
// use the value of cluster_cookie parameter in the init.lua file
.withCredentials(USER_NAME, PASSWORD)
// Number of connections per Tarantool instance
.withConnections(10)
// Specify using the default CRUD proxy operations mapping configuration
.withProxyMethodMapping()
.build();
}
And reuse it then I need retrying client.
private TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> getRetryingTarantoolClient(
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> client) {
retryingCounter = new AtomicInteger();
return TarantoolClientFactory.configureClient(client)
// Configure a custom delete function
.withProxyMethodMapping(builder -> builder.withDeleteFunctionName("delete_with_error_if_not_found"))
// Set retrying policy
// First parameter is number of attempts
.withRetryingByNumberOfAttempts(5,
// You can use default predicates from TarantoolRequestRetryPolicies for checking errors
retryNetworkErrors()
// Also you can use your own predicates and combine them with each other
.or(e -> e.getMessage().contains("Unsuccessful attempt"))
.or(e -> {
retryingCounter.getAndIncrement();
return e.getMessage().contains("Records not found");
})
// Or with defaults
.or(retryTarantoolNoSuchProcedureErrors()),
// Also you can set delay in millisecond between attempts
factory -> factory.withDelay(300)
)
.build();
}
You don't have to set up basic client if you need retying client only. All methods of client builder with prefix withRetrying can be used with createClient.

In this code I call delete_with_error_if_not_found (custom delete function) before the record was inserted to the database. So client recalls delete and removes the record after it was inserted.

// Creating multiple clients
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> crudClient = getCrudClient();
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> retryingClient =
getRetryingTarantoolClient(crudClient);
TarantoolSpaceOperations<TarantoolTuple, TarantoolResult<TarantoolTuple>> space =
crudClient.space(SPACE_NAME);
space.truncate().join();
// Use TarantoolTupleFactory for instantiating new tuples
TarantoolTupleFactory tupleFactory = new DefaultTarantoolTupleFactory(
crudClient.getConfig().getMessagePackMapper());
// Call delete_with_error_if_not_found before record was inserted
Conditions conditions = Conditions.equals(PK_FIELD_NAME, 1);
CompletableFuture deleteFuture = retryingClient.space(SPACE_NAME).delete(conditions);
retry(() -> assertEquals(1, retryingCounter.get()));
space.insert(tupleFactory.create(1, null, "FIO", 50, 100)).join();
deleteFuture.join();
TarantoolResult<TarantoolTuple> selectResult = space.select(conditions).join();
assertEquals(0, selectResult.size());