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

make v2 streaming like v3 #868

Merged
merged 7 commits into from
Jun 26, 2024
Merged

make v2 streaming like v3 #868

merged 7 commits into from
Jun 26, 2024

Conversation

insipx
Copy link
Contributor

@insipx insipx commented Jun 25, 2024

fixes #859

@insipx insipx changed the title V2 -> V3 like streaming make v2 streaming like v3 Jun 25, 2024
@insipx insipx marked this pull request as ready for review June 26, 2024 16:28
@insipx insipx requested a review from a team as a code owner June 26, 2024 16:28
@insipx insipx requested a review from nplasterer June 26, 2024 16:30
@insipx insipx requested a review from richardhuaaa June 26, 2024 17:17
Copy link
Contributor

@richardhuaaa richardhuaaa left a comment

Choose a reason for hiding this comment

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

LGTM!

bindings_ffi/src/v2.rs Outdated Show resolved Hide resolved
bindings_ffi/src/v2.rs Show resolved Hide resolved
bindings_ffi/src/v2.rs Outdated Show resolved Hide resolved
pub async fn update(&self, req: FfiV2SubscribeRequest) -> Result<(), GenericError> {
let mut sub = self.inner_subscription.lock().await;
sub.update(req.into()).await?;
self.tx.send(req).await.map_err(|_| GenericError::Generic {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the pro/con of sending it through via mpsc, compared to calling it on the subscription directly like in the previous implementation?

Copy link
Contributor Author

@insipx insipx Jun 26, 2024

Choose a reason for hiding this comment

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

That's a good question, other than the usual edge-casey footguns with mpsc,

I think the biggest downside is the extra memory overhead for the channel itself, which in this case is bounded to 10 updates (chosen pretty arbitrarily). Since it is bounded, if update is called continually like in a loop we might lose some updates after reaching the limit on the channel. This shouldn't really be an issue, though, since the caller should be putting the topics in a Vec<> to the channel FfiV2SubscribeRequest type anyway. The limit is needed to avoid a infinitely growing channel which, if unbounded, would lead to high memory use if update is misused.

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes sense - I guess more specifically, what would be the drawback of storing the subscription directly on FFIV2Subscription, and directly updating it here as in the old implementation, versus the new approach of storing the tx and sending a message over it?

Copy link
Contributor Author

@insipx insipx Jun 26, 2024

Choose a reason for hiding this comment

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

By storing the subscription locally in the task, we can avoid using a Mutex to access the subscription. This has a few benefits, and it more generally/slightly resembles the actor model of concurrency rather than locking:

  • It's easier to reason about what's happening to the subscription, because all the events are handled in one event loop the task is spawning
  • we avoid any footguns we might run into with Mutex's, which lets us avoid a class of errors that occurs with Mutexes, which makes update more difficult to misuse outside of libxmtp. We still use Mutexes a bunch which is fine, esp considering this is with uniffi, but more mutexes means more potential for deadlocks and mutex contention. Mutexes are more performant, though, but I doubt using a channel vs mutex will make a huge diff in that direction here
  • if we want to modify the subscription in other ways, can extend it by just adding new events to the loop on the same channel with an enum or something, instead of adding another mutex for that resource

I guess its a bit arbitrary, when writing streams I do default to this strategy rather than Mutex's, unless absolutely necessary for performance or to satisfy the borrow checker w.r.t uniffi or the like

@insipx insipx enabled auto-merge (squash) June 26, 2024 21:30
@insipx insipx merged commit c3a03b3 into main Jun 26, 2024
4 checks passed
@insipx insipx deleted the insipx/v2-streaming branch June 26, 2024 22:11
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.

Update V2 Rust Streaming to Callbacks
2 participants