nlopes / libhoney-rust

Rust library for sending data to Honeycomb
MIT License
23 stars 16 forks source link

Have close/flush return a Future for callers to wait on #71

Open ramosbugs opened 3 years ago

ramosbugs commented 3 years ago

Currently, calling flush triggers an asynchronous flush but doesn't provide the caller with a mechanism to wait for all queued events to be flushed.

This PR changes the Client::flush and Client::close interfaces to be async and fixes a few concurrency issues I ran into while making this change:

Resolves #66 and fixes #65.

ramosbugs commented 3 years ago

Sorry, this turned into a more involved PR than I expected!

nlopes commented 3 years ago

Will take a look as soon as I can.

nlopes commented 3 years ago

@ramosbugs apologies for such a long delay. I promise I'll look at this as soon as I'm not swamped. I appreciate the contribution!

ramosbugs commented 3 years ago

no worries, thanks!

nlopes commented 3 years ago

Although I didn't have the intention to expose async outside of the client, I kind of like the approach here. Would you be so kind as to run cargo readme >! README.md and push it here? That would save me an update commit just to sync the README.md with what's now in lib.rs.

nlopes commented 3 years ago

The main thing I'd like to change before I merge (if you're up for it!) is to make async-std and tokio features that can be toggled. Your change here adds async-std on top of tokio which isn't great. See https://github.com/nlopes/libhoney-rust/pull/61 for what I mean.

If you're not up for it (and I totally understand if you aren't), I'll bring it myself in another PR with this one as base. Just let me know what you'd prefer and I'm happy to oblige.

I really appreciate your contribution.

ramosbugs commented 3 years ago

Although I didn't have the intention to expose async outside of the client, I kind of like the approach here. Would you be so kind as to run cargo readme >! README.md and push it here? That would save me an update commit just to sync the README.md with what's now in lib.rs.

done!

The main thing I'd like to change before I merge (if you're up for it!) is to make async-std and tokio features that can be toggled. Your change here adds async-std on top of tokio which isn't great. See #61 for what I mean.

It looks like there are a few complexities around tokio vs. async_std here:

ramosbugs commented 3 years ago

also, is the objection to adding async_std due to the additional dependency cost, or is it specifically about mixing the tokio and async_std runtimes? it feels like runtime-agnostic primitives like async_std::future::timeout and async_std::sync::Mutex are preferable to runtime-specific ones like tokio::time::timeout. using a spawn closure like I suggested above could potentially remove the tokio dependency altogether

nlopes commented 3 years ago

it feels like runtime-agnostic primitives like async_std::future::timeout and async_std::sync::Mutex are preferable

You hit exactly what my message was intended to deliver and which I failed to deliver 😆 That's basically what I'd want: we either use runtime-agnostic primitives or we put different runtimes behind features.

ramosbugs commented 3 years ago

I think given the issues around dropping runtimes at various points in the code, the runtime-agnostic approach would be preferable. I'll try to incorporate that change :-)

ramosbugs commented 3 years ago

looks like the async_executors crate provides some nice adapters for different runtimes to be able to leverage the futures::task::Spawn trait. the commit I just pushed takes in an Arc<dyn Spawn> and avoids creating any runtimes directly. I also updated the unit tests to be run easily on all supported runtimes (currently just Tokio).

as reflected in #61, my change isn't sufficient to support runtimes other than Tokio because of Reqwest's dependency on Tokio, but it fixes the task management piece. switching to surf (in a follow-up change) would finish adding support for other runtimes.

there's also a caveat with my latest change: it relies on async_std's unstable feature flag in order to make use of an async condition variable (Condvar). I couldn't find any other suitable async-friendly primitives that wouldn't block the executor thread. note that this has nothing to do with "unstable" Rust and doesn't depend on nightly or anything. I think it just means that Condvar may not respect SemVer, so I pinned to the latest async-std 1.9.0 version. that means clients won't be able to integrate other versions easily, but that restriction can be removed once async-rs/async-std#217 is completed.

nlopes commented 3 years ago

This is looking great. I'm going to do a deeper review this weekend and get this out there most likely.

I can't thank you enough for the contributions and patience on my late reviews.