Struct ultra_batch::BatchExecutor
source · pub struct BatchExecutor<E>where
E: Executor,{ /* private fields */ }
Expand description
Batches calls to an Executor
, such as for bulk inserting, updating,
or deleting records in a datastore. BatchExecutor
s are asynchronous
and designed to be passed and shared between threads or tasks. Cloning
a BatchExecutor
is shallow and will use the same underlying Executor
.
BatchExecutor
is designed primarily for bulk database operations– for
example, inserting lots of records, where a single query to insert
50 new records is much faster than 50 separate queries. However, it can
be used for fetching data or any other bulk operation as well.
Unlike BatchFetcher
, BatchExecutor
has no
concepts of keys, values, deduplication, or caching; each executed value
is passed directly to the underlying Executor
. As such, it could also
be suitable for writing a custom caching layer in situations where
BatchFetcher
is not suitable.
BatchExecutor
s introduce a small amount of latency for executions. Each
time a new value or set of values is sent for execution, it will first
wait for more values to buid a batch. The execution will only trigger after
a timeout is reached or once enough values have been queued in the batch.
See BatchExecutorBuilder
for options to tweak latency and batch sizes.
§Execution semantics
If the underlying Executor
returns an error during the batch execution,
then all pending execute
and execute_many
requests will fail. The same values can be resubmitted to retry.
If the underlying Executor
succeeds but does not return a Vec
that
contains results for all values, then calls to execute
may return None
. Calls to execute_many
may return a Vec
containing less output values than input values.
Implementations§
source§impl<E> BatchExecutor<E>
impl<E> BatchExecutor<E>
sourcepub fn build(executor: E) -> BatchExecutorBuilder<E>
pub fn build(executor: E) -> BatchExecutorBuilder<E>
Create a new BatchExecutor
athat uses the given Executor
to
execute values. Returns a BatchExecutorBuilder
, which can be
used to customize the BatchExecutor
. Call .finish()
to create the BatchExecutor
.
§Examples
Creating a BatchExecutor
with default options:
let user_inserter = UserInserter::new(db_conn);
let batch_inserter = BatchExecutor::build(user_inserter).finish();
Creating a BatchExecutor
with custom options:
let user_inserter = UserInserter::new(db_conn);
let batch_inserter = BatchExecutor::build(user_inserter)
.eager_batch_size(Some(50))
.delay_duration(tokio::time::Duration::from_millis(5))
.finish();
sourcepub async fn execute(
&self,
key: E::Value
) -> Result<Option<E::Result>, ExecuteError>
pub async fn execute( &self, key: E::Value ) -> Result<Option<E::Result>, ExecuteError>
Submit a value to be executed by the Executor
. Returns the
result value returned by the Executor
for this given item. See
the type-level docs for BatchExecutor
for
detailed execution semantics.
sourcepub async fn execute_many(
&self,
values: Vec<E::Value>
) -> Result<Vec<E::Result>, ExecuteError>
pub async fn execute_many( &self, values: Vec<E::Value> ) -> Result<Vec<E::Result>, ExecuteError>
Submit multiple values to be executed by the Executor
. Returns a
Vec
containg values for each result returned by the Executor
for each given input value (but note that the returned Vec
may
not have values for all inputs if the Executor
did not return
enough results). See the type-level docs for BatchExecutor
for detailed execution semantics.