Timed infinite loop fix#80
Conversation
Not currently failing, just demonstrates the unfortunate behavior.
…when due Also rename `fire_at` to `enqueue_at` to be explicit about the fact. This is a trade-off that prevents 2 sorts of bad behavior: - actors with send-sending messages never handling any delayed/recurring messages (#72) - actors with recurring messages that are slower to handle than their interval eventually not processing any outside messages (#79) See the tweaked tests for the change of behavior.
bschwind
left a comment
There was a problem hiding this comment.
LGTM, though I have a small question, and a spelling fix.
|
|
||
| Ok(()) | ||
| } | ||
| // Message 2 is a recurring one, sleep based on a paremeter. |
There was a problem hiding this comment.
| // Message 2 is a recurring one, sleep based on a paremeter. | |
| // Message 2 is a recurring one, sleep based on a parameter. |
| // Recurring and Delayed messages are only added to the queue when handled, and then go | ||
| // through actors priority inboxes again when actually enqueued. |
There was a problem hiding this comment.
I'm having trouble visualizing the message flow based on this comment.
only added to the queue when handled
In my mind, "handled" means the actor has run the handle() function on the message, so it's already out of the queue.
Is it possible to be more specific in the language here about the flow of the message from when send_delayed is called to when it actually ends up in the actor handle() function?
There was a problem hiding this comment.
Agree. What about
| // Recurring and Delayed messages are only added to the queue when handled, and then go | |
| // through actors priority inboxes again when actually enqueued. | |
| // These priorities apply to the set-up of Delayed and Recurring messages and we want to handle that pronto. | |
| // The resulting inner message then comes back as `Instant` and is prioritized per its internal priority. |
There was a problem hiding this comment.
@goodhoko you suggestion reads very good to me using it (with very small tweaks)
goodhoko
left a comment
There was a problem hiding this comment.
Thanks for materialising our long discussion into an actual fix @strohel!
Behaviorally this looks all correct! I only have some suggestion for improving the comments. Let's give them good amount of attention as they're important for understanding the convoluted logic of Timed wrapper. .)
| // Recurring and Delayed messages are only added to the queue when handled, and then go | ||
| // through actors priority inboxes again when actually enqueued. |
There was a problem hiding this comment.
Agree. What about
| // Recurring and Delayed messages are only added to the queue when handled, and then go | |
| // through actors priority inboxes again when actually enqueued. | |
| // These priorities apply to the set-up of Delayed and Recurring messages and we want to handle that pronto. | |
| // The resulting inner message then comes back as `Instant` and is prioritized per its internal priority. |
6e473f3 to
294b065
Compare
294b065 to
b4b0bc2
Compare
goodhoko
left a comment
There was a problem hiding this comment.
This is perfect! Especially the doc comments on TimedMessage variants are very helpfull. Good to merge IMO!
I suppose this can be released with a mere patch bump. Or do we consider the change in delivery order to be breaking?
Good point. The rename of the I'll prepare portal version that uses this PR before merging to get some real-life testing. It doesn't technically require any code changes (the renamed fields are not directly used). Also opportunity for @bschwind to check clarity of comments of the latest version. |
Ahaaa! I assumed that the enum field is private by default (as are struct fields) but actually enum variants and their fields always share the visibility of the enum itself. I.e. the field is part of the crate's public API.
Per the semver spec, if it's backward incompatible we should bump the major version. Minor version bumps are for additions (backward compatible changes). It feels excessive but hey, it's just a version number. |
Yup, but
|
|
@strohel Got it. I didn't realize actor is still pre-1.0. Thanks! |
|
Tonari internal note: if we decide to revive this, the logic in https://github.com/tonarino/portal/pull/3692 may stop working. |
|
This full version of the PR seems to cause some other issues like https://github.com/tonarino/portal/pull/2958#issuecomment-1901172737 But there may be a more minimal and less controversial version: "just" change if self.queue.peek().map(|m| m.enqueue_at <= Instant::now()).unwrap_or(false)instead of while self.queue.peek().map(|m| m.enqueue_at <= Instant::now()).unwrap_or(false)I.e. process only one message of the queue at a time. The existing code should then schedule processing of the next one right away, but still yield back to the actor system in the mean time. Thoough the suggestion needs some scrutiny and a lot of testing. |
timed tests: rename test, assert only after shutdown, extend timeline comments
Add test for issue #79
Not currently failing, just demonstrates the unfortunate behavior.
timed: fix #79 by enqueueing (rather than handling) delayed messages when due
Also rename
fire_attoenqueue_atto be explicit about the fact.This is a trade-off that prevents 2 sorts of bad behavior:
Timedactor'shandle()is slower than recurring message interval #79)See the tweaked tests for the change of behavior.
Checking how the test results change commit-by-commit should give a good story.