Akka.NET TestKit synchronous behavior - akka.net

I have the following C# code to test an AKKA.NET actor's behavior. The statement productActor.Tell(new ChangeActiveStatus(true)); is expected to be a blocking call (TestKit makes it a synchronous call as per this blog) but I'm seeing it returns immediately. As a result, the second test fails although the ActiveStatus will be changed later.
[TestMethod]
public void ProductActorUnitTests_CheckFor_ActiveStatusChanged()
{
var productActor = ActorOfAsTestActorRef<ProductActor>();
Assert.IsTrue(ProductActor.UnderlyingActor.ActiveStatus == false, "The initial ActiveStatus is expected to be FALSE.");
productActor.Tell(new ChangeActiveStatus(true));
Assert.IsTrue(productActor.UnderlyingActor.ActiveStatus == true, "The new ActiveStatus is expected to be TRUE.");
}
****** UPDATE *****
The following code with a Thread.Sleep(10000) succeeds:
[TestMethod]
public void ProductActorUnitTests_CheckFor_ActiveStatusChanged()
{
var productActor = ActorOfAsTestActorRef<ProductActor>();
Assert.IsTrue(ProductActor.UnderlyingActor.ActiveStatus == false, "The initial ActiveStatus is expected to be FALSE.");
productActor.Tell(new ChangeActiveStatus(true));
Thread.Sleep(10000);
Assert.IsTrue(productActor.UnderlyingActor.ActiveStatus == true, "The new ActiveStatus is expected to be TRUE.");
}

Most of the AKKA.NET unit tests that I have seen use only two actors. The blog that shows the example (in the original question) has only two actors, so it will work because the operations are synchronous. If there are multiple actors in the system, for example the Actor A messages Actor B which messages Actor C which messages Actor A again, the messaging happen asynchronously, so have to wait until all the operations are complete.

Related

Test with Kotlin Coroutines is randomly failing

Let us suppose we have a class member whose purpose is
to bring 2 objects (let's say object1 and object2) from two different places and then create the final
result merging these two object in another one, which is finally returned.
Suppose then the operation of retrieving object1 and object2 can be done concurrently,
so this leads to a typical use case of kotlin coroutines.
What has been described so far is shown in the following example:
fun parallelCall(): MergedObject {
return runBlocking(context = Dispatchers.Default) {
try {
val object1 : Deferred<Object1> = async {
bringObject1FromSomewhere()
}
val object2 : Deferred<Object2> = async {
bringObject2FromSomewhere()
}
creteFinalObject(object1.await(), object2.await())
} catch (ex: Exception) {
throw ex
}
}
}
The surrounding try block should intercept any kind of exception thrown while
object1 and object2 are retrieved, as well as in the createFinalObject method.
This latter simply merges together the awaited results from previous calls,
waiting for both of them to be accomplished.
Note that the awaiting of the deferred object1 and object2 happens almost at the same time,
since they are both awaited when passed as arguments to the createFinalObject method.
In this scenario I can perform a test using mockk as mocking library such that whenever bringObject1FromSomewhere()
throws an exception, then the creteFinalObject method is NEVER called. Namely, something like:
#Test
fun `GIVEN bringObject1FromSomewhere throws exception WHEN parallelCall executes THEN creteFinalObject is never executed`() {
every { bringObject1FromSomewhere() } throws NullPointerException()
every { bringObject2FromSomewhere() } returns sampleObject2
assertThrows<NullPointerException> { parallelCall() }
verify(atMost = 1) { bringObject1FromSomewhere() }
verify(atMost = 1) { bringObject2FromSomewhere() }
//should never be called since bringObject1FromSomewhere() throws nullPointer exception
verify(exactly = 0) { creteFinalObject(any(), any()) }
}
The problem is that the test above works almost always, but, there are some cases in which it randomly fails,
calling the createFinalObject method regardless of the mocked values.
Is this issue related to the slight difference in time in which the deferred object1 and object2
are awaited when creteFinalObject(object1.await(), object2.await()) is called?
Another thing which comes to my mind could be the way in which I am expecting argument in the last line of the test:
verify(exactly = 0) { creteFinalObject(any(), any()) }
does mockk could have any problem when any() is used?.
Further, can potentially be an issue the fact that the try { } block is not able to detect the exception
before the createFinalObject method is called? I would never doubt about this in a non-parallel environment but probably
the usage of runBlocking as coroutineScope changes the rule of the game?
Any hints will be helpful, thanks!
Kotlin version:1.6.0 Corutines version: 1.5.2 mockk version: 1.12.2
Are you sure it fails because it attempts to call the creteFinalObject function? Because when reading your code, I think that should be impossible (of course, never say never :D). The creteFinalObject function can only be called if both object1.await() and object2.await() return successfully.
I think something else is going on. Because you're doing 2 separate async tasks (getting object 1 and getting object 2), I suspect that the ordering of these 2 tasks would result in either a success or a failure.
Running your code locally, I notice that it sometimes fails at this line:
verify(atMost = 1) { bringObject2FromSomewhere() }
And I think there is your error. If bringObject1FromSomewhere() is called before bringObject2FromSomewhere(), the exception is thrown and the second function invocation never happens, causing the test to fail. The other way around (2 before 1) would make the test succeed. The Dispatchers.Default uses an internal work queue, where jobs that are cancelled before they are even started will never start at all. And the first task can fail fast enough for the second task to not being able to start at all.
I thought the fix would be to use verify(atLeast = 0, atMost = 1) { bringObject2FromSomewhere() } instead, but as I see on the MockK GitHub issues page, this is not supported (yet): https://github.com/mockk/mockk/issues/806
So even though you specify that bringObject2FromSomewhere() should be called at most 1 time, it still tries to verify it is also called at least 1 time, which is not the case.
You can verify this by adding a delay to the async call to get the first object:
val object1 : Deferred<Object1> = async {
delay(100)
bringObject1FromSomewhere()
}
This way, the test always succeeds, because bringObject2FromSomewhere() always has enough time to be called.
So how to fix this? Either hope MockK fixes the functionality to specify verify(atLeast = 0, atMost = 1) { ... }, or disable the verification on this call for now.

How can I get a non-blocking infinite loop in a Kotlin Actor?

I would like to consume some stream-data using Kotlin actors
I was thinking to put my consumer inside an actor, while it polls in an infinite loop while(true). Then, when I decide, I send a message to stop the consumer.
Currently I have this:
while(true) {
for (message in channel){ <--- blocked in here, waiting
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
The problem
The problem with this is that it only runs when I send a message to the actor, so my consumer is not polling the rest of the time because channel is blocking waiting to receive the next message
Is there any alternative?, someone with the same issue?, or something similar to actors but not blocked by channel in Kotlin?
Since the channel is just a Channel (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html) you can first check if the channel is empty and if so start your polling. Otherwise handle the messages.
E.g.
while(true) {
while (channel.isNotEmpty()) {
val message = channel.receive()
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
In the end I used AKKA with Kotlin, I'm finding much easier this way
You should use postDelayed(), for example:
final Runnable r = new Runnable() {
public void run() {
// your code here
handler.postDelayed(this, 1000)
}
}
You can change 1000 with the the millisecond delay you want. Also I highly recommend to put your code inside a thread (if you are not already have) to prevent ANR (App Not Responding)

Akka.Net switching behavior with Become()

I have built as simple actor which accepts two messages: TicketValidated and BarrierPush but the switching is not happening as intended.
public class TurnstileActor : ReceiveActor
{
public TurnstileActor()
{
Become(Locked);
}
public void Locked()
{
Receive<TicketValidated>(msg => Become(Unlocked));
Receive<BarrierPush>(msg => { Console.WriteLine("Locked");});
}
public void Unlocked()
{
Receive<TicketValidated>(msg =>
Console.WriteLine("Unlocked"));
Receive<BarrierPush>(msg => Become(Locked));
}
}
Main class
var system = ActorSystem.Create("ActorSystem");
var actor = system.ActorOf<TurnstileActor>("actor");
actor.Tell(new TicketValidated());
Actual execution is: the Locked() method is called from the constructor and TicketValidated message is received. Become(Unlocked) is executed correctly and it enters Unlocked() method but then Console.WriteLine("Unlocked") is not called.
Could the Akka.Net library be broken?
To understand this behaviour, consider what happens when Become(Unlocked) is executed, and it enters the Unlocked() method. The Unlocked method in turn invokes the Receive method twice: These 2 calls to Receive register the new behaviour of this actor, affecting subsequent messages sent to this actor instance. The lambdas passed in to the Receive methods are not executed at this time - they represent the new behaviour that is registered, and that will be seen when subsequent messages are received.
That explains why "Unlocked" is not written to the console when "Become(Unlocked)" is executed - It will only be seen if the next message received is another "TicketValidated".

How does actors in kotlin work when ran on different threads?

In the actor example from the official kotlinlang.org documentation, an actor is launched 100 000 times which simply increments a counter inside the actor. Then a get request is sent to the actor and the counter is sent in the response with the correct amount (100 000).
This is the code:
// The messages
sealed class CounterMsg
object IncCounter : CounterMsg() // one-way message to increment counter
class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a two-way message to get the counter
// The actor
fun CoroutineScope.counterActor() = actor<CounterMsg> {
var counter = 0 // actor state
for (msg in channel) { // iterate over incoming messages
when (msg) {
is IncCounter -> counter++
is GetCounter -> msg.response.complete(counter)
}
}
}
fun main() {
runBlocking {
val counterActor = counterActor()
GlobalScope.massiveRun {
counterActor.send(IncCounter) // run action 100000 times
}
val response = CompletableDeferred<Int>()
counterActor.send(GetCounter(response))
println("Counter = ${response.await()}")
counterActor.close()
}
}
I have problems understanding what would happen if the counterActor coroutines would execute on multiple threads? If the coroutines would run on different threads the variable 'counter' in the actor would potentially be susceptible to a race condition, would it not?
Example: One thread runs a coroutine and this receives on the channel, and then on another thread a coroutine could receive and both of them try to update the counter variable at the same time, thus updating the variable incorrectly.
In the text that follows the code example
It does not matter (for correctness) what context the actor itself is executed in. An actor is a coroutine and a coroutine is executed sequentially, so confinement of the state to the specific coroutine works as a solution to the problem of shared mutable state.
Im having a hard time understanding this. Could someone elaborate what this exactly means, and why a race condition does nor occur. When I run the example I see all coroutines run on the same main thread so I can not prove my theory of the race condition.
"actor is launched 100 000 times"
No, actor is launched exactly 1 time, at the line
val counterActor = counterActor()
Then it receives 100000 messages, from 100 coroutines working in parallel on different threads. But they do not increment the variable counter directly, they only add messages to the actor's input message queue. Indeed, this operation, implemented in the kotlinx.coroutines library, is made thread-safe.

Async WCF Service with multiple async calls inside

I have a web service in WCF that consume some external web services, so what I want to do is make this service asynchronous in order to release the thread, wait for the completion of all the external services, and then return the result to the client.
With Framework 4.0
public class MyService : IMyService
{
public IAsyncResult BeginDoWork(int count, AsyncCallback callback, object serviceState)
{
var proxyOne = new Gateway.BackendOperation.BackendOperationOneSoapClient();
var proxyTwo = new Gateway.BackendOperationTwo.OperationTwoSoapClient();
var taskOne = Task<int>.Factory.FromAsync(proxyOne.BeginGetNumber, proxyOne.EndGetNumber, 10, serviceState);
var taskTwo = Task<int>.Factory.FromAsync(proxyTwo.BeginGetNumber, proxyTwo.EndGetNumber, 10, serviceState);
var tasks = new Queue<Task<int>>();
tasks.Enqueue(taskOne);
tasks.Enqueue(taskTwo);
return Task.Factory.ContinueWhenAll(tasks.ToArray(), innerTasks =>
{
var tcs = new TaskCompletionSource<int>(serviceState);
int sum = 0;
foreach (var innerTask in innerTasks)
{
if (innerTask.IsFaulted)
{
tcs.SetException(innerTask.Exception);
callback(tcs.Task);
return;
}
if (innerTask.IsCompleted)
{
sum = innerTask.Result;
}
}
tcs.SetResult(sum);
callback(tcs.Task);
});
}
public int EndDoWork(IAsyncResult result)
{
try
{
return ((Task<int>)result).Result;
}
catch (AggregateException ex)
{
throw ex.InnerException;
}
}
}
My questions here are:
This code is using three threads: one that is instanced in the
BeginDoWork, another one that is instanced when the code enter
inside the anonymous method ContinueWhenAll, and the last one when
the callback is executed, in this case EndDoWork. Is that correct or
I’m doing something wrong on the calls? Should I use any
synchronization context? Note: The synchronization context is null
on the main thread.
What happen if I “share” information between
threads, for instance, the callback function? Will that cause a
performance issue or the anonymous method is like a closure where I
can share data?
With Framework 4.5 and Async and Await
Now with Framework 4.5, the code seems too much simple than before:
public async Task<int> DoWorkAsync(int count)
{
var proxyOne = new Backend.ServiceOne.ServiceOneClient();
var proxyTwo = new Backend.ServiceTwo.ServiceTwoClient();
var doWorkOne = proxyOne.DoWorkAsync(count);
var doWorkTwo = proxyTwo.DoWorkAsync(count);
var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return doWorkOne.Result + doWorkTwo.Result;
}
But in this case when I debug the application, I always see that the code is executed on the same thread. So my questions here are:
3.. When I’m waiting for the “awaitable” code, is that thread released and goes back to the thread pool to execute more requests?
3.1. If So, I suppose that when I get a result from the await Task, the execution completes on the same thread that the call before. Is that possible? What happen if that thread is processing another request?
3.2 If Not, how can I release the thread to send it back to the thread pool with Asycn and Await pattern?
Thank you!
1. This code is using three threads: one that is instanced in the BeginDoWork, another one that is instanced when the code enter inside the anonymous method ContinueWhenAll, and the last one when the callback is executed, in this case EndDoWork. Is that correct or I’m doing something wrong on the calls? Should I use any synchronization context?
It's better to think in terms of "tasks" rather than "threads". You do have three tasks here, each of which will run on the thread pool, one at a time.
2. What happen if I “share” information between threads, for instance, the callback function? Will that cause a performance issue or the anonymous method is like a closure where I can share data?
You don't have to worry about synchronization because each of these tasks can't run concurrently. BeginDoWork registers the continuation just before returning, so it's already practically done when the continuation can run. EndDoWork will probably not be called until the continuation is complete; but even if it is, it will block until the continuation is complete.
(Technically, the continuation can start running before BeginDoWork completes, but BeginDoWork just returns at that point, so it doesn't matter).
3. When I’m waiting for the “awaitable” code, is that thread released and goes back to the thread pool to execute more requests?
Yes.
3.1. If So, I suppose that when I get a result from the await Task, the execution completes on the same thread that the call before. Is that possible? What happen if that thread is processing another request?
No. Your host (in this case, ASP.NET) may continue the async methods on any thread it happens to have available.
This is perfectly safe because only one thread is executing at a time.
P.S. I recommend
var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return result[0] + result[1];
instead of
var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return doWorkOne.Result + doWorkTwo.Result;
because Task.Result should be avoided in async programming.