net.adamec.lib.common.actor 1.0.1+28.190122143650.master.f8d71bf

Lightweight in-process asynchronous message based inter-components communication framework - Actor System

This package has a SemVer 2.0.0 package version.
This package will only be available to download with SemVer 2.0.0 compatible NuGet clients, such as Visual Studio 2017 (version 15.3) and above or NuGet client 4.3.0 and above. Read more
Install-Package net.adamec.lib.common.actor -Version 1.0.1
dotnet add package net.adamec.lib.common.actor --version 1.0.1
<PackageReference Include="net.adamec.lib.common.actor" Version="1.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add net.adamec.lib.common.actor --version 1.0.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Lightweight Actor System

The purpose is to provide the lightweight in-process asynchronous message based communication between the components (Inspired by Akka.net which provides actor system implementation for the applications where more robust solution is needed).

Actor is a generally any component implementing IActor interface registered within the Actor System that is able to receive and process the messages sent from another Actor or even from outside world. The message processing is by design asynchronous where the messages for individual actors are processed in FIFO sequence, but the Actor System also provides the support for synchronous (Request-Reply) pattern.

Documentation at github
Code documentation at github

High Level Architecture

Architecture diagram

Actor is any object implementing IActor interface publishing the method for processing the inbound messages. ActorSystem is the main component taking care about the actors and distributing the messages. It's usually a singleton, but its possible to have multiple actor systems if needed.
Each actor must register to ActorSystem first to get recognized by system (and deregister at the end of its life cycle). Actor System creates the internal reference to actor (ActorRefInternal) and returns the IActorRef interface used as a reference to Actor within the Actor System. ActorRefInternalobject contains the reference to actor (IActor) and encapsulates the MessageQueue of actor. Anybody who has the reference to actor (IActorRef) can send the message to actor using the method IActorRef.Tell. The internal implementation encapsulates the message into the Envelope and push it to the message queue related to the actor.

Actor system manages the ActorSystemDispatcher running the executor thread responsible for checking the actors' message queues, pick the messages and deliver them to actors for processing.
Dispatcher periodically loops through the queues. If there is any message, the dispatcher uses the ThreadPool to queue work item - process the messages for actor, so the messages for different actors can be processed in parallel in several threads. Whenever the actor is scheduled for processing, it's locked for further processing, until the scheduled processing task is finished.
The processing of actor messages is quite simple - message is picked from queue and sent to actor for processing (invoking the Receive delegate returned by IActor.ReceiveTarget). It waits until the message is processed, picks another message and send it to actor for processing. This ensures that the messages are processed sequentially in the order as they are enqueued (the message queue is FIFO). The system parameter max messages defines the size of single "batch" of messages to be processed before the actor is unlocked and waits for next "tick" of dispatcher.

Actor System maintains two system queues:

  • Deadletters is the queue containing the messages that are not handled by actor or undeliverable. Whenever the message is sent to an actor for processing, the actor has to return true if the message was processed or false in case it didn't process (handle) the message. The unhandled messages are moved to dead letters queue then.
  • ErrorMessageQueue contains the messages that caused an exception while being processed by an actor. The exception is catched by dispatcher (exactly by scheduled work task distributing the messages to particular actor), encapsulated together with the message causing the exception into ErrorMessage (inherits from Envelope) and enqueued to the error message queue.

Scheduled Messages

Actor System supports scheduling of two types:

  • One-time (non-periodical) messages are scheduled for given date and time. The dispatcher enqueues the message to recipient's queue next executor run after the defined date and time.
  • Periodical messages are scheduled for given period. The dispatcher enqueues the message to recipient's queue next executor run after each period. Technically just the next message is scheduled for corresponding date and time and when it's equeued, another "instance" of scheduled message is created for the next period.

As describe above, you can't rely on the exact processing time of the scheduled messages, because the schedule tells when the message will be put into the queue (as the last message), so if there are any other messages pending in the queue, it will delay the message processing. Also the time when the messages are enqueued is not 100% exact - the dispatcher executor checks in each run (loop) for the scheduled messages with the next required fire time equal or older than current time so there is also small cost related to the dispatch of the messages.

Request-Reply Messaging

Astor System support Request-Reply messaging pattern using IActorSystem.Ask methods. The temporary internal actor is created and the requested message is sent from this temporary actor to the recipient. When the recipient replies, the temporary actor check the type of response and if matches, it's "returned" back to the Ask method and the temporary actor is dismissed.
In case that the required response doesn't come in given time period (timeout) the Askmethod returns default(T) or throws TimeoutException depending on given parameter.
So even if the message processing is "internally" asynchronous, the Ask method is blocked (synchronous) and waits for the proper response or timeout.

Lightweight Actor System

The purpose is to provide the lightweight in-process asynchronous message based communication between the components (Inspired by Akka.net which provides actor system implementation for the applications where more robust solution is needed).

Actor is a generally any component implementing IActor interface registered within the Actor System that is able to receive and process the messages sent from another Actor or even from outside world. The message processing is by design asynchronous where the messages for individual actors are processed in FIFO sequence, but the Actor System also provides the support for synchronous (Request-Reply) pattern.

Documentation at github
Code documentation at github

High Level Architecture

Architecture diagram

Actor is any object implementing IActor interface publishing the method for processing the inbound messages. ActorSystem is the main component taking care about the actors and distributing the messages. It's usually a singleton, but its possible to have multiple actor systems if needed.
Each actor must register to ActorSystem first to get recognized by system (and deregister at the end of its life cycle). Actor System creates the internal reference to actor (ActorRefInternal) and returns the IActorRef interface used as a reference to Actor within the Actor System. ActorRefInternalobject contains the reference to actor (IActor) and encapsulates the MessageQueue of actor. Anybody who has the reference to actor (IActorRef) can send the message to actor using the method IActorRef.Tell. The internal implementation encapsulates the message into the Envelope and push it to the message queue related to the actor.

Actor system manages the ActorSystemDispatcher running the executor thread responsible for checking the actors' message queues, pick the messages and deliver them to actors for processing.
Dispatcher periodically loops through the queues. If there is any message, the dispatcher uses the ThreadPool to queue work item - process the messages for actor, so the messages for different actors can be processed in parallel in several threads. Whenever the actor is scheduled for processing, it's locked for further processing, until the scheduled processing task is finished.
The processing of actor messages is quite simple - message is picked from queue and sent to actor for processing (invoking the Receive delegate returned by IActor.ReceiveTarget). It waits until the message is processed, picks another message and send it to actor for processing. This ensures that the messages are processed sequentially in the order as they are enqueued (the message queue is FIFO). The system parameter max messages defines the size of single "batch" of messages to be processed before the actor is unlocked and waits for next "tick" of dispatcher.

Actor System maintains two system queues:

  • Deadletters is the queue containing the messages that are not handled by actor or undeliverable. Whenever the message is sent to an actor for processing, the actor has to return true if the message was processed or false in case it didn't process (handle) the message. The unhandled messages are moved to dead letters queue then.
  • ErrorMessageQueue contains the messages that caused an exception while being processed by an actor. The exception is catched by dispatcher (exactly by scheduled work task distributing the messages to particular actor), encapsulated together with the message causing the exception into ErrorMessage (inherits from Envelope) and enqueued to the error message queue.

Scheduled Messages

Actor System supports scheduling of two types:

  • One-time (non-periodical) messages are scheduled for given date and time. The dispatcher enqueues the message to recipient's queue next executor run after the defined date and time.
  • Periodical messages are scheduled for given period. The dispatcher enqueues the message to recipient's queue next executor run after each period. Technically just the next message is scheduled for corresponding date and time and when it's equeued, another "instance" of scheduled message is created for the next period.

As describe above, you can't rely on the exact processing time of the scheduled messages, because the schedule tells when the message will be put into the queue (as the last message), so if there are any other messages pending in the queue, it will delay the message processing. Also the time when the messages are enqueued is not 100% exact - the dispatcher executor checks in each run (loop) for the scheduled messages with the next required fire time equal or older than current time so there is also small cost related to the dispatch of the messages.

Request-Reply Messaging

Astor System support Request-Reply messaging pattern using IActorSystem.Ask methods. The temporary internal actor is created and the requested message is sent from this temporary actor to the recipient. When the recipient replies, the temporary actor check the type of response and if matches, it's "returned" back to the Ask method and the temporary actor is dismissed.
In case that the required response doesn't come in given time period (timeout) the Askmethod returns default(T) or throws TimeoutException depending on given parameter.
So even if the message processing is "internally" asynchronous, the Ask method is blocked (synchronous) and waits for the proper response or timeout.

  • .NETStandard 2.0

This package is not used by any popular GitHub repositories.

Version History

Version Downloads Last updated
1.0.1 75 1/22/2019
1.0.0 67 12/30/2018
0.1.0 65 12/21/2018