This is not to say that Akka removes the need to think about concurrency. It doesn’t, and you must still design for parallelism, latency, eventually consistent application state, and think of how you will prevent your application from unnecessary blocking. What Akka and Actor Model do is remove the common concurrency programming problems such as dead-lock, live-lock, inefficient code, and the need to consider threads as a first-class programming model. In a nutshell, it makes concurrent software designs as simple as possible to successfully achieve.
Actors are created asynchronously, and after they are fully created, they are started.
preStart() is invoked when the actor is started, after actor is created.
An actor is stopped asynchronously when stop(ActorRef) is called. postStop() is invoked when the actor is stopped.
preRestart() is invoked just prior to the actor’s restart.
postRestart() is invoked just following restart on the newly created actor, enabling reinitialization after actor failure and restart.
Resume() is different than
Restart
in that Resume()
leaves current child actor state in tact, and the child will process its next available message. Restart()
causes the child to be terminated and completed reconstituted, which means its mailbox is empty; its not the same actor.
Network penalty to send messages
Again, this is referring to direct asynchronous messaging of Actor Model. In reality, it is not direct, especially when the network is involved. It could take considerable time for a message to reach the target actor.
ActorSystem can span nodes.
Actually one
ActorSystem
can span nodes. In other words, you are not required to choose a different ActorSystem
name for each node just because there is a separation of two or more JVMs. Two or more nodes can have the same named ActorSystem
, which implies that an ActorSystem
spans a number of nodes. Even so, it might make more sense to name various ActorSystem
instances according to the role they play in the application.
Why ActorRef May Be Less Reliable
An
ActorRef
may reference an actor that has been stopped and no longer exists. If you send a message through the ActorRef
under those conditions, it will not be delivered because there is no actor to which the message can be delivered. On the other hand, an ActorSelection
is based on an ActorPath
. Sending by means of a means of a path will cause the Akka internals to look up the actor by its path, and if found, then send the message. An actor that was stopped may have been restarted and exist by a different ActorRef
than before, but it will still have the same path as its previous incarnation.
Delivery guarantee
This seems more than a little risky in the age of widespread use of transactions. After all, in business enterprises it’s unacceptable to allow a message communicating, for example, financial transactions, to go completely undelivered, especially when the messaging style of design emphasizes fire and forget. Who wants to take responsibility for using fire and forget in an at-most-once delivery environment? With those characteristics, how could Actor Model be suitable for use in business enterprises?
Not to worry. There are a few ways to ensure that a given Actor eventually receives a message that must be delivered to ensure business success. The approach discussed next uses a special Message Channel to ensure message delivery. See also Guaranteed Delivery (#) for further discussion.
Eventually Consistency
When the
Channel
receives the message, it creates and appends an entry in the Message Journal (#) that indicates that the message must eventually be confirmed by its receiver
The
Channel
keeps the message, as well as all unconfirmed messages, in memory and retries sending each one until each message is confirmed, or until a maximum number of retries is reached.
Whenever the
OrderProcessor
is recovered—see Guaranteed Delivery (#)—all confirmed message entries are deleted from the Message Journal
Messaging
For example, on both Java and .NET systems the type
Message
is provided by most middleware systems, and holds both Header and Body parts.
On the other hand, when using Actor Model, a message consists only of the second part, the Body. In other words, the message is just the application-level data being transmitted between actors.
Case class as message type
Using Scala, the message types of a Canonical Data Model (#) can be very efficiently created using case classes.Case classes have two big advantages. First, they exist specifically to be efficiently used with Scala pattern matching. Second, they are one of the easiest ways to create immutable value types.
Sealed Trait
Using a sealed trait enforces that any code that attempts to match on any one of the case classes will have to match on all of them. This is a way to prevent developers from forgetting to consider some cases, such as when there is a design change and new messages are added to a messaging contract. The Scala compiler will flag any omissions as an error.
These tools serve, not only as documentation, but as a name scoping technique. Now, in order to use the messages associated with order processing, you must import the specific object:
When a message sending actor needs to cause an action to be performed on the receiving actor, the sender uses a Command Message.
that’s what the C in CQS stands for; a request that causes a state transition.
Each Command Message, although sent by a requestor, is defined by the receiver actor as part of its public contract.
Idempotent Receiver—Design an actor to be an Idempotent Receiver when there is the possibility for it to receive a given message multiple times, and processing that message each time would cause problems. Since the standard message delivery contract for Actor Model is “at most once,” it may seem like this could never be a problem. The problem can arise, however, when we use the
AtLeastOnceDelivery
mix in.
No comments:
Post a Comment