AKKA Programming (Create an Auction Simulator using AKKA).
What is AKKA?
AKKA is used for building distributed, highly concurrent, and fault-tolerant applications. AKKA is written in Scala and works in Java too. AKKA uses the Actor Model. The Actor Model is the core of AKKA. The Actor model is a framework for creating distributed and concurrent applications.
Actors are fundamental units in the Actor Model.
The actor is responsible for,
- Communicates with other actors using asynchronous messages.
- Encapsulate state and behaviors.
- It ensures thread-safe using it only processes one message at a time.
Actors are isolated from each other actors and they do not share memory, then it avoids concurrency issues like deadlocks and race conditions.
How did the AKKA name come?
The name of AKKA is chosen by the creator of AKKA Jonas Boner is Swedish. That name came from AKKA massif, which is a mountain range in Sweden. Choosing a mountain name symbolizes stability, durability, and reliability.
How does it manage concurrency?
- Message Passing
Each actor communicates via immutable messages, Messages are passing asynchronously, then actors do not need to wait to response.
2. Single thread execution
Each actor processes one message at a time.
3. No shared state
Actors maintain their own state.
4. Non-blocking operations
Asynchronous message pass avoids blocking.
I have created an example application for demonstrating AKKA programming features. It is an auction simulator.
It has two main components
- AuctionManager
The Auction Manager manages and coordinates auctions, forwards bids to the specific auction that the bid relates to, and it manages the auction lifetime.
2. AuctionActor
Auction Actor manages a single auction. It tracks the highest bid, the bidder associated to the highest bid.
Let’s see how this encapsulates state and behaviors.
State
highestBid has the risk of getting concurrent issues. Then it is private and can only be modified in onPlaceBid which is actor’s private method.
private double highestBid;
Behaviors
Actors behaviors are how actor reacts to messages that come to actors.
onPlaceBid — Check the current bid is higher than the highest bid, it updates the highest bid and winner.
private Behavior<AuctionCommand> onPlaceBid(PlaceBid bid) {
if (bid.amount > highestBid) {
highestBid = bid.amount;
winner = bid.bidder;
context.getLog().info("New highest bid: {} by {}", highestBid, bid.bidder);
} else {
context.getLog().info("Bid by {} is too low: {}", bid.bidder, bid.amount);
}
return Behaviors.same();
}
onEndAuction — It displays the final result and stops the Actor.
private Behavior<AuctionCommand> onEndAuction(EndAuction command) {
context.getLog().info("Auction '{}' ended with highest bid: {} winner is : {}", auctionId, highestBid, winner);
return Behaviors.stopped();
}
All states and Behaviors are private, and they can only be modified using the Actor itself. That is how it encapsulates states and behaviors.
In AuctionManager,
It handles multiple auctions. Following are the messages it handles.
- OnCreateAuction — Creates a new AuctionActor for specific auction
private Behavior<AuctionManagerCommand> onCreateAuction(CreateAuction command) {
ActorRef<AuctionCommand> auction = context.spawn(
AuctionActor.create(command.auctionId, command.initialPrice),
command.auctionId
);
auctions.put(command.auctionId, auction);
context.getLog().info("Auction '{}' created with initial price: {}", command.auctionId, command.initialPrice);
context.getSystem().scheduler().scheduleOnce(
Duration.ofSeconds(command.durationInSeconds),
() -> context.getSelf().tell(new EndAuctionForManager(command.auctionId)),
context.getExecutionContext()
);
return Behaviors.same();
}
2. OnForwardBid — Forwards PlaceBid message to appropriate auction.
private Behavior<AuctionManagerCommand> onForwardBid(ForwardBid command) {
ActorRef<AuctionCommand> auction = auctions.get(command.auctionId);
if (auction != null) {
auction.tell(new PlaceBid(command.placeBid.bidder, command.placeBid.amount));
context.getLog().info("Forwarded bid from '{}' to auction '{}'", command.placeBid.bidder, command.auctionId);
} else {
context.getLog().info("Auction '{}' not found.", command.auctionId);
}
return Behaviors.same();
}
3. OnEndAuctionForManager — send EndAuction message to appropriate auction.
private Behavior<AuctionManagerCommand> onEndAuctionForManager(EndAuctionForManager command) {
ActorRef<AuctionCommand> auction = auctions.get(command.auctionId);
if (auction != null) {
auction.tell(new EndAuction());
context.getLog().info("Ended auction '{}'", command.auctionId);
auctions.remove(command.auctionId); // Optionally remove the auction after ending it
} else {
context.getLog().info("Auction '{}' not found for ending.", command.auctionId);
}
return Behaviors.same();
}
Summary
In this example actors communicate via asynchronous messages, actors encapsulate their state and behaviors to ensure thread-safe. Using AKKA it simplifies Concurrency and Modularity.
You can find the full example in this GitHub repository Click.