-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Clear current message - fixes #1609 #1613
Clear current message - fixes #1609 #1613
Conversation
@@ -60,6 +60,7 @@ public void Invoke(Envelope envelope) | |||
AutoReceiveMessage(envelope); | |||
else | |||
ReceiveMessage(message); | |||
CurrentMessage = null; | |||
} |
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.
From the Scala code
final def invoke(messageHandle: Envelope): Unit = try {
currentMessage = messageHandle
cancelReceiveTimeout() // FIXME: leave this here???
messageHandle.message match {
case msg: AutoReceivedMessage ⇒ autoReceiveMessage(messageHandle)
case msg ⇒ receiveMessage(msg)
}
///########## current message is cleared here
currentMessage = null // reset current message after successful invocation
} catch handleNonFatalOrInterruptedException { e ⇒
handleInvokeFailure(Nil, e)
} finally {
checkReceiveTimeout // Reschedule receive timeout
}
Some notes. When doing this, we also need to make sure that async operations have access to the current message in their continuations, this is solved by capturing the current user message when an async operation starts, and then pass that message back to the actor cell using the |
ActorCell.CurrentMessage won't be set after the first await in the async receive. It will be restored properly before calling HandleInvokeFailure in case of an exception, but it won't be set for other usage: AbstractStash.Stash Stash won't work after the first await, not sure how it impacts the other usages. This could be fixed by creating an ActorTaskScheduler instance per async receive, the current message would be kept in the instance so it can be restored on each ActorTaskSchedulerMessage handling. An instance per message is not that bad for async receive, the throughput of async receive should not be high anyway. However this issue may impact the performance of this approach. An alternative would be to use a custom ActorSynchronizationContext instead of an ActorTaskScheduler. |
I have updated the code to restore the current message on all ActorTaskSchedulerMessage messages. Do note that there should never be any new or changed current messages while doing an async operation as the mailbox is suspended for user messages. |
|
{ | ||
_actorCell.Self.Tell(new ActorTaskSchedulerMessage(this, task), ActorRefs.NoSender); | ||
{ | ||
_actorCell.Self.Tell(new ActorTaskSchedulerMessage(this, task, _actorCell.CurrentMessage), ActorRefs.NoSender); |
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 wait, I think this approach doesn't work if the task is scheduled from outside of the actor's context.
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.
AFAIK, no one could ever use this outside of the actor context as each scheduler is bound to an individual actor and only used from within a context.
Are there any cases I am missing?
(I can not find any usage in the references that hints that would be the case)
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.
Receive(async m =>
{
// ...
await Task.Delay(1000); // ActorTaskScheduler.QueueTask will be called outside the actor's context when the timer expires
// ...
});
@rogeralsing Just saw your edit, that's right ActorTaskScheduler could capture CurrentMessage in a field as long as it is cleared when the async receive completes to not recreate the original issue. |
} | ||
|
||
//clear the current message field of the scheduler | ||
actorScheduler.CurrentMessage = null; |
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.
Clear the current message of the scheduler
cc @JeffCyr , I've updated the scheduler to keep a field for the current message. |
Looks good! 👍 |
Should we add a spec to ensure that the current message is cleared? |
var actor = Sys.ActorOf(Props.Create(() => new DummyActor(autoResetEvent))); | ||
actor.Tell("hello"); | ||
//ensure the message was received | ||
autoResetEvent.WaitOne(); |
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.
wait until the actor have received our message
@Aaronontheweb I've added a spec to ensure that the current message is cleared. |
re-set curret message on async callbacks store current message in a field clear CurrentMessage Added clear message spec added async await test
//wait while current message is not null (that is, receive is not yet completed/exited) | ||
SpinWait.SpinUntil(() => cell.CurrentMessage == null, TimeSpan.FromSeconds(2)); | ||
|
||
cell.CurrentMessage.ShouldBe(null); |
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.
wait for current message to become null, or timeout
Then assert that current message is null
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.
You can use AwaitAssert
for this in the future, but this change is fine
Looks like #1608 dirtied the working directory and failed this spec, which is bad. This is an issue with how I've configured TeamCity, not anything to do with our code. I'll get to work on fixing this. |
All of the tests pass - will review this when I get back from a meeting |
Looks fine to me. |
…receive-fixes1609 Clear current message - fixes #1609
Fixes #1609
cc @JeffCyr please review that the current message on async
ActorTaskSchedulerMessage
messages looks OK.