Repository: MystenLabs/sui
File: crates/sui-core/src/transaction_orchestrator.rs (Rust)

Code before:
        client_addr: Option<SocketAddr>,
    ) -> Result<(QuorumTransactionResponse, IsTransactionExecutedLocally), QuorumDriverError> {
        let result = inner
            .execute_transaction_with_effects_waiting(
                request.clone(),
                client_addr,
                /* enforce_live_input_objects */ false,
            )
            .await;

        // If the error is retriable, retry the transaction sufficiently long.
        if let Err(e) = &result
            && e.is_retriable()
        {
            spawn_monitored_task!(async move {
                inner.metrics.background_retry_started.inc();
                let backoff = backoff::ExponentialBackoff::new(
                    Duration::from_secs(1),
                    Duration::from_secs(300),
                );
                const MAX_RETRIES: usize = 60;
                for (i, delay) in backoff.enumerate() {
                    if i == MAX_RETRIES {
                        break;
                    }
                    // Start to enforce live input after 10 retries,
                    // to avoid excessively retrying transactions with non-existent input objects.
                    let result = inner
                        .execute_transaction_with_effects_waiting(
                            request.clone(),
                            client_addr,
                            i > 3,
                        )
                        .await;
                    match result {
                        Ok(_) => break,
                        Err(e) => {
                            if !e.is_retriable() {
                                break;
                            }
                            inner.metrics.background_retry_errors.inc();
                            if i % 100 == 0 {
                                debug!(
                                    "Background retry {i} for transaction {}: {e:?}",
                                    request.transaction.digest()
                                );
                            }
                        }
                    };
                    sleep(delay).await;
                }

Review comment (suggestion):
The comment says 10 retries, but the condition below is `i > 3` . I would say that 10 is probably better.

Code after:
        client_addr: Option<SocketAddr>,
    ) -> Result<(QuorumTransactionResponse, IsTransactionExecutedLocally), QuorumDriverError> {
        let result = inner
            .execute_transaction_with_effects_waiting(
                request.clone(),
                client_addr,
                /* enforce_live_input_objects */ false,
            )
            .await;

        // If the error is retriable, retry the transaction sufficiently long.
        if let Err(e) = &result
            && e.is_retriable()
        {
            spawn_monitored_task!(async move {
                inner.metrics.background_retry_started.inc();
                let backoff = backoff::ExponentialBackoff::new(
                    Duration::from_secs(1),
                    Duration::from_secs(300),
                );
                const MAX_RETRIES: usize = 10;
                for (i, delay) in backoff.enumerate() {
                    if i == MAX_RETRIES {
                        break;
                    }
                    // Start to enforce live input after 3 retries,
                    // to avoid excessively retrying transactions with non-existent input objects.
                    let result = inner
                        .execute_transaction_with_effects_waiting(
                            request.clone(),
                            client_addr,
                            i > 3,
                        )
                        .await;
                    match result {
                        Ok(_) => break,
                        Err(e) => {
                            if !e.is_retriable() {
                                break;
                            }
                            inner.metrics.background_retry_errors.inc();
                            if i % 100 == 0 {
                                debug!(
                                    "Background retry {i} for transaction {}: {e:?}",
                                    request.transaction.digest()
                                );
                            }
                        }
                    };
                    sleep(delay).await;
                }