slawlor / ractor

Rust actor framework
MIT License
1.52k stars 73 forks source link

flush() method to help testing #249

Closed gusinacio closed 2 months ago

gusinacio commented 4 months ago

Is your feature request related to a problem? Please describe. Right now it's not possible to reliably test actors because of tokio and the queue system. The way I'm currently using to test them is by adding some tokio::time::sleep(Duration::from_millis(10)).await after sending some messages but it turns out that it's not as reliable as I wish, sometimes the tests fail because it took a little bit longer then expected.

This is not a big deal when dealing with a single actor because messages are processed sequentially, but sometimes you want to cast a message to actor A and it will send a message to actor B and you need to test if that message was sent or not.

Describe the solution you'd like I think that if actors had a flush() method or similar, it would be easier to test where I send a message, flush it, and know for sure that all messages on the queue were processed.

Describe alternatives you've considered If there's a better way to flush the messages or make sure that all side effects were processed I'd love to hear.

Additional context

slawlor commented 3 months ago

Flush doesn't make much sense to me from a practical standpoint, since you'd need to block until the actor has handled all messages in the queue, which may include the actor pushing new messages to itself and I think you could open yourself to deadlock.

You could always add a custom flush message which has an RpcReplyPort with a callback when that message in the queue is processed. Then it's as simple as an RPC call.

Additionally our test suites have periodic polling routines to check a state until a given timeout window via polling. This is commonly used for scenarios of "eventually consistent state".

slawlor commented 1 month ago

@gusinacio we did add a drain signal in #268. This might actually solve your problem you were referencing here. It puts a stub-marker into the message queue and rejects future messages received after the drain is signaled.

You can then wait on the join handle after draining to make sure all messages are processed.