1
votes

I know that actors inside Service Fabric are single-threaded. But suppose I start a new thread inside an actor method, what will happen then? Will an actor be deactivated even though the spawned thread is still executing?

According to the documentation, an actor is deactivated when it has not been 'used' for some time. 'Used' in this context means either:

  • receiving a call
  • IRemindable.ReceiveReminderAsync being invoked

So it seems that the new thread I started is not taken into account. But maybe someone can confirm this?

2

2 Answers

3
votes

Actors are just object.

The Actor will be deactivated and it becomes available for garbage collection.

Actual threads in the OS (when running) keep running until they complete or terminate. Their managed representation can be collected, but this doesn't affect the actual thread.

Also, threads spawned inside an Actor are not tracked in any way, so you're responsible to manage their life cycle yourself.

2
votes

Exactly.

When you start a new thread, the original thread(The actor) will continue running and go out of scope, and the spanned thread continue running. look what happens then:

When an actor receive a call, the thread handling this call will acquire a lock using a SemaphoreSlim to handle the actor object, if another thread has already acquired the lock, the current thread will wait for its release, so that it can continue once free.

Once the lock is acquired, the thread will execute and return from the method called, and them release the lock for the following thread to continue.

When you span a new thread as part of the actor logic, it will just run as part of the service process, but the problem here is that once you leave the method scope, you won't have control of this thread anymore, but it will keep running, and for the actor runtime the task has finished, the next actor call will create another thread, and the things will keep going.

The problem will start when:

  • You don't have control how many threads are running, your services will start consuming too much memory and SF might try to balance the actors\services across instances, because it does not know about these threads, if it move the actor service, all you threads will be aborted and you loose these operations.
  • The spanned thread from previous call will compete with the new thread for the next actor call.
  • If the new thread uses the actor data to continue other operation both, the spanned thread and the actor thread will face concurrency issues, in cases where no exception happens you will have strange behaviors where you can't investigate easily. For example, one thread changing a value being used by the other.
  • And many other concurrency issues you might face

In scenarios where you might(think) need another thread you could:

  • Create another actor to handle the task
  • Create a message in a queue to be processed by another service
  • Do the task as part of the actor call.