-
Notifications
You must be signed in to change notification settings - Fork 78
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
FromActorRef<TFrom> which allows to send messages convertible to original TMessage #306
Conversation
Created a draft PR to validate the initial approach. I will expand it if the approach is correct. I have some concerns/questions about the current implementation:
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #306 +/- ##
==========================================
+ Coverage 82.17% 82.19% +0.01%
==========================================
Files 60 61 +1
Lines 11032 11124 +92
==========================================
+ Hits 9066 9143 +77
- Misses 1966 1981 +15 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great start! I think however we can improve upon the API, and potentially drop the boxed converter, just relying on type constraints for functionality implementation. Let me know if my comments make sense!
ractor/src/actor/from_actor_ref.rs
Outdated
let actor_ref = self.clone(); | ||
let cast_and_send = move |msg: TFrom| match actor_ref.send_message(msg.clone().into()) { | ||
Ok(_) => Ok(()), | ||
Err(MessagingErr::SendErr(_)) => Err(MessagingErr::SendErr(msg)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I feel like the clone should be avoidable. What about a dual implementation, where we have
FromActorRef<TFrom: TryFrom<TMessage>, TMessage: From<TFrom>>
And we panic if we can't deconvert the TryFrom. That way you can avoid the clone, by capturing the original
MessagingErr::SendErr(message) => MessageErr::SendErr(msg.from_into().expect("Failed to convert message back to base type"))
I don't love the clone restriction, as it has a lot of downstream consequences (think like a tcp stream, etc) and vastly restricts the usage. I'd rather utilize the expect
and rely on the fact that a messaging error means the send failed, and therefore we're going to get back the same datatype, and can safely unwrap it back.
However it does require the user to implement both patterns of conversion.
ractor/src/actor/mod.rs
Outdated
@@ -69,6 +69,7 @@ pub mod actor_cell; | |||
pub mod actor_id; | |||
pub(crate) mod actor_properties; | |||
pub mod actor_ref; | |||
pub mod from_actor_ref; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The type should also be added to the public re-exports at the crate base.
ractor/src/actor/tests/mod.rs
Outdated
.send_message(u16_message) | ||
.expect("Failed to send message to actor"); | ||
|
||
periodic_check( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This isn't documented in the tests super well, but use of periodic_check
was all over the place prior to the addition of the drain()
functionality. Now we have the ability to drain messages, and wait for the actor cleanup, so you can just drain, wait for stop, and then read the counter without polling it.
It will yield more effecient tests, since you don't have a polling with a timeout/etc. I need to refactor a lot of the tests to account for this tbh.
Thanks for the review! Regarding the boxed converter, this was added to get rid of pub struct FromActorRef<TFrom, TMessage> {
inner: ActorRef<TMessage>,
_phantom: PhantomData<TFrom>,
} then the send message implementation will look like this: impl<TFrom: TryFrom<TMessage>, TMessage: From<TFrom> + Message> FromActorRef<TFrom, TMessage>
where
<TFrom as TryFrom<TMessage>>::Error: std::fmt::Debug,
{
/// Casts the message to the target message type of [ActorCell] and sends it
///
/// * `message` - The message to send
///
/// Returns [Ok(())] on successful message send, [Err(MessagingErr)] otherwise
pub fn send_message(&self, message: TFrom) -> Result<(), MessagingErr<TFrom>> {
match self.inner.send_message(message.into()) {
Ok(_) => Ok(()),
Err(MessagingErr::SendErr(msg)) => Err(MessagingErr::SendErr(
msg.try_into()
.expect("Failed to convert message back to base type"),
)),
Err(MessagingErr::ChannelClosed) => Err(MessagingErr::ChannelClosed),
Err(MessagingErr::InvalidActorType) => Err(MessagingErr::InvalidActorType),
}
}
} however this will force us to have the original message as part of the let actor: ActorRef<AB> = init();
let from_a: FromActorRef<A, AB> = actor.clone().from_ref(); what do you think? Boxed converter is the only thing I found to hide |
Ahh ok I see your goal. Let me try something, I think I have a workaround. |
…ementation details.
OK I couldn't find a way around the Box, you're right. We need to propagate the original message type, without enforcing the type constraint on the original struct. I did however apply most of the other PR comments. Let me know what you think! I think this is clean enough at this stage, but we might just need a little more cleanup in spots and maybe an example usage in the doc comments would be good to also be covered by doctests. |
sounds good, thanks! added some doctests + added a |
Can you make sure the signals are green? I'm guessing the doc tests are failing |
Fixed the formatting + added import which was failing the test. Hopefully it will pass this time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great to me, thanks for the additions!
Adding
FromActorRef<TFrom>
- a wrapper overActorRef<TMessage>
that allows to send messages of typeTFrom
to the actor ifTFrom: Into<TMessage>
. This allows to create some isolation in the actor system as discussed in #305.