Skip to content

Conversation

@lpahlavi
Copy link
Contributor

@lpahlavi lpahlavi commented Oct 27, 2025

Add the option of configuring a retry strategy to the EvmRpcClient in order to double the amount of cycles attached to a call until it succeeds.

where
Config: CandidType + Send,
Params: CandidType + Send,
Config: CandidType + Clone + Send,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Clone bounds are needed here to be able to clone the request when retrying.


/// The retry strategy when performing calls to the EVM RPC canister.
#[derive(Clone, Eq, PartialEq, Debug, Default)]
pub enum EvmRpcRetryStrategy {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hesitated here to make this a trait instead of an enum, so users can provide their own retry implementation. In the end, I felt like it might have been over-engineered though and an enum might be sufficient. WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One problem I see is that if we need some additional trait bounds for a new variant in EvmRpcRetryStrategy, then this will trickle down to all methods, such as try_execute_request, even if the caller would not use this particular variant. For that reason, my impression is that having a trait here would be useful. Something like in the spirit of tower::retry::Policy. One benefit is that the trait EvmRpcResult would also I think no longer be necessary, because the bound would be on the strategy implementing RetryPolicy. Example

pub trait RetryPolicy<Config, Params, CandidOutput, Output> {
    fn retry(
        &mut self, //can mutate self in case the strategy is stateful
        request: Request<Config, Params, CandidOutput, Output>, //take ownership, no separate_method `clone_request
        result: &mut Result<Output, IcError>, //strategy can decide to change result
    ) -> Option<Request<Config, Params, CandidOutput, Output>>;
}

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually originally had something very similar, and then moved to an enum... But I think you make some good points and in the end the more complicated solution is indeed probably better.

Note that I did add a clone_request method, otherwise, even with a NoRetry policy, requests would still need to be cloneable. This means we effectively have something extremely similar to tower::retry::Policy, and so I'm wondering if in the end it might not make more sense to just use that? We could use tower for the whole thing which would just require adding a 'static bound on the Config and Params types. WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes, the trait looks very good to me!

and so I'm wondering if in the end it might not make more sense to just use that?

For now I would not, for the following reasons:

  1. less dependencies
  2. simpler, because the current retry policy does not need to be async.

@lpahlavi lpahlavi marked this pull request as ready for review October 28, 2025 09:08
@lpahlavi lpahlavi requested a review from a team as a code owner October 28, 2025 09:08
@lpahlavi lpahlavi requested a review from gregorydemay October 29, 2025 17:12
Copy link
Contributor

@gregorydemay gregorydemay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the refactoring @lpahlavi ! Some minor comments but otherwise looks very good to me!


/// The retry strategy when performing calls to the EVM RPC canister.
#[derive(Clone, Eq, PartialEq, Debug, Default)]
pub enum EvmRpcRetryStrategy {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes, the trait looks very good to me!

and so I'm wondering if in the end it might not make more sense to just use that?

For now I would not, for the following reasons:

  1. less dependencies
  2. simpler, because the current retry policy does not need to be async.

@lpahlavi lpahlavi requested a review from gregorydemay October 30, 2025 10:10
@lpahlavi
Copy link
Contributor Author

Thanks a lot for the review and input @gregorydemay! This should be ready for another round.

@lpahlavi lpahlavi merged commit 8e25e74 into main Oct 30, 2025
11 checks passed
@lpahlavi lpahlavi deleted the lpahlavi/client-retry-strategy branch October 30, 2025 10:59
@github-actions github-actions bot mentioned this pull request Oct 21, 2025
lpahlavi added a commit that referenced this pull request Nov 3, 2025
## 🤖 New release

* `evm_rpc_client`: 0.1.0 -> 0.2.0 (✓ API compatible changes)
* `evm_rpc`: 2.6.0 -> 2.7.0 (✓ API compatible changes)

<details><summary><i><b>Changelog</b></i></summary><p>

## `evm_rpc_client`

<blockquote>

## [0.2.0] - 2025-11-03

### Added

- Add `.request_cost()` method to `RequestBuilder` to compute the cycles
cost of a request via the new `CyclesCost`
query endpoints
([#509](#509))
- Add the option to configure a retry strategy in the EVM RPC client to
e.g., try a request with increasingly many
cycles if it fails to to insufficient cycles
([#512](#512))

[0.2.0]:
evm_rpc_client-v0.1.0...evm_rpc_client-v0.2.0
</blockquote>

## `evm_rpc`

<blockquote>

## [2.7.0] - 2025-11-03

### Added

- For each `eth_*` endpoint, add a new corresponding `eth_*CyclesCost`
query endpoint with the same Candid arguments, that allows computing the
cycles cost of calling the corresponding `eth_*` update endpoint
([#508](#508),
[#509](#509))

### Changed

- Use constant-size request IDs in JSON-RPC requests to allow for
consistent request cycles costs
([#514](#514))

[2.7.0]:
v2.6.0...v2.7.0
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Louis Pahlavi <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants