Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migration to 0.3 & Async/Await #582

Closed
wants to merge 38 commits into from
Closed

Conversation

gakonst
Copy link
Member

@gakonst gakonst commented Jan 2, 2020

As title. Still WIP. Opening for initial feedback. This will be split in smaller PRs and squashed/split into more verbose commits.

  • We can get rid of the BoxedIlpFuture and replace it everywhere with IlpResult (which is really a Result<Fulfill, Reject>.
  • We can utilize async-trait to allow our traits to have async functions. So far so good, haven't hit any edge cases yet. Had to manually add 'async_trait as a lifetime.
  • Note that the reduction in generics, as well as the eventual removal of the huge closure-chains will improve our compilation times significantly.
  • Bytes-05 is now needed for all HTTP related crates, so we temporarily maintain both versions in the required crates. Before the migration is over, Bytes 0.5 should be the only version in the repository. This could be more complex than expected due to breaking changes:
  • Warp needs to be added from master for now
  • Tokio-tungstenite got futures 0.3 support recently so we can expect it to be released soon

Will fix #85.

  • service
  • ildcp
  • http
  • router
  • btp: blocked on Conversion to tokio 0.2 snapview/tokio-tungstenite#68
  • ccp
  • service-util: how do timeouts with 0.3 futures work?
  • api: blocked on some Warp changes (need to document)
  • settlement: requires compat methods for tokio-retry
  • store
  • stream
  • spsp
  • ilp-node: blocked on BTP and Prometheus
  • ilp-cli

Copy link
Contributor

@bstrie bstrie left a comment

Choose a reason for hiding this comment

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

I quite like the look of this so far. In my head the idea was first to have a massive PR transitioning from 0.1 to 0.3, and then have a second massive PR moving to async/await, just to split the effort into more manageable chunks even if it meant more effort overall. But from what you've got here I'm thinking that you've got the right idea by just switching immediately to async/await, since it seems like we can avoid a whole lot of frustration from things that got changed since we're using so much less of the futures crate by simply getting rid of all the combinators via await.

@@ -10,8 +10,13 @@ repository = "https://github.com/interledger-rs/interledger-rs"
[dependencies]
bytes = { version = "0.4.12", default-features = false }
byteorder = { version = "1.3.2", default-features = false }
futures = { version = "0.1.29", default-features = false }
futures = { version = "0.3", default-features = false }
Copy link
Contributor

Choose a reason for hiding this comment

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

futures is on 0.3.1 by now, might as well update directly to that.

account_ids: Vec<Uuid>,
) -> Box<dyn Future<Item = Vec<Self::Account>, Error = ()> + Send>;
) -> Result<Vec<Self::Account>, ()>;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd love to begin thinking about returning actual error types rather than just () everywhere, which would hopefully get rid of a ton of explicit error!() calls, and likewise remove a ton of map_err and the associated closures (which could go even further toward improving compile time). It doesn't need to be in this PR, but it's something to look forward to (and there's no reason we wouldn't want to do so, right?).

where
A: Account,
B: IntoFuture<Item = Fulfill, Error = Reject>,
<B as futures::future::IntoFuture>::Future: std::marker::Send + 'static,
F: FnMut(IncomingRequest<A>) -> B,
Copy link
Contributor

Choose a reason for hiding this comment

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

The simplification here is delicious.

B: IntoFuture<Item = Fulfill, Error = Reject>,
<B as futures::future::IntoFuture>::Future: std::marker::Send + 'static,
F: FnMut(IncomingRequest<A>) -> B,
F: FnMut(IncomingRequest<A>) -> IlpResult + Send,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, but to make the association easier to visually parse I would write bounds like this as:

F: Send + FnMut(IncomingRequest<A>) -> IlpResult,

ilp_address: Address,
) -> Box<dyn Future<Item = (), Error = ()> + Send>;
) -> Box<dyn Future<Output = Result<(), ()>> + Send>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use async_trait on this trait rather than returning an explicitly boxed future?

Copy link
Member Author

Choose a reason for hiding this comment

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

#[cfg(feature = "trace")]
pub use trace::*;

pub type IlpResult = Result<Fulfill, Reject>;
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

"Unable to parse ILDCP response from fulfill packet: {:?}",
err
);
})?;
Copy link
Contributor

Choose a reason for hiding this comment

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

As I mention elsewhere, I'd love to introduce proper error return types so that we would no longer have to deal with so much wasted space due to map_errs, like those in this function. Doesn't need to be part of this effort, but async/await makes our code so much cleaner that instances like these really really stand out.

}
}

#[cfg(test)]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why add these tests as part of this PR?

@gakonst gakonst mentioned this pull request Jan 5, 2020
12 tasks
Write locks should not be in the same scope as await'ed futures.
We fix this by scoping the write lock for as long as needed, and
then yield only the result of the computation. When the scope is over,
the lock gets dropped, so we can safely use the future.
WIP. Need to fix the Server (warp does not support tungstenite yet), and
the Client's add_connection method is commented out still
async fn -> IlpResult desugars to fn -> Future<Output = IlpResult
Note: exchange rate service does not compile on 1.39, but compiles on nightly. Why?
@gakonst gakonst closed this Jan 15, 2020
@gakonst gakonst deleted the gakonst/futures03-ildcp branch January 20, 2020 17:04
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.

Switch to async/await syntax once stabilized
2 participants