2
\$\begingroup\$

Recently I did an exercise to understand Akka. I implemented a trading system with Akka to process orders with Actors.

My code is like:

Order: Immutable class with acts as the messages in the system.

public final class Order {

    public enum OrderType {
        BUY,
        SELL
    };

    private final int orderId;

    private final OrderType orderType;

    private final String instrument;

    private final double price;

    public Order(int orderId, OrderType orderType, String instrument, double price) {
        this.orderId = orderId;
        this.orderType = orderType;
        this.instrument = instrument;
        this.price = price;
    }

    public int getOrderId() {
        return orderId;
    }

    public OrderType getOrderType() {
        return orderType;
    }

    public String getInstrument() {
        return instrument;
    }

    public double getPrice() {
        return price;
    }
}

Then I created an OrderProcessingActor to process the orders received. For now, the process is an abstract thing which only prints the order received and tells the sender order executed information.

import akka.actor.AbstractActor;
import akka.actor.Props;

public class OrderProcessingActor extends AbstractActor {

    public static Props props() {
        return Props.create(OrderProcessingActor.class, OrderProcessingActor::new);
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .match(
                        Order.class,
                        order -> {
                            processOrder(order);
                        }).build();
    }

    private void processOrder(Order order) {
        System.out.println(String.format("OrderProcessingActor %d %s order received for instrument %s with price %s", order.getOrderId(), order.getOrderType(), order.getInstrument(), order.getPrice()));
        //process order here.
        getSender().tell(String.format("OrderProcessingActor %d %s order processed for instrument %s with price %s", order.getOrderId(), order.getOrderType(), order.getInstrument(), order.getPrice()), getSelf());
    }
}

I also created a TradingSystemSupervisor which is responsible for creating and managing OrderProcessingActor. The orders are received by the TradingSystemSupervisor which are then sent to the OrderProcessingActor.

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;

import java.util.HashMap;
import java.util.Map;


public class TradingSystemSupervisor extends AbstractActor {

    private static Map<String, ActorRef> actorRefMap = new HashMap<>();

    public static Props props() {
        return Props.create(TradingSystemSupervisor.class, TradingSystemSupervisor::new);
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .match(
                        Order.class,
                        order -> {processOrder(order);}).build();
    }

    private void processOrder(Order order) {
        System.out.println(String.format("TradingSystemSupervisor %d, %s order received for instrument %s with price %s", order.getOrderId(), order.getOrderType(), order.getInstrument(), order.getPrice()));
        //process order here.
        if(!actorRefMap.containsKey(order.getInstrument())) {
            ActorRef actorRef = getContext().getSystem().actorOf(OrderProcessingActor.props(), String.format("%s-order-processing-actor", order.getInstrument()));
            actorRefMap.put(order.getInstrument(), actorRef);
        }
        actorRefMap.get(order.getInstrument()).tell(order, getSelf());
    }
}

I am looking for a review of the solution from Java as well as Akka's perspective. Is my solution ok considering the way I have used Akka or can I improve the solution? I am also trying to implement Akka routing to this solution.

\$\endgroup\$
1
\$\begingroup\$

Other than maybe adding some comments for documentation, this seems pretty sane. This:

    System.out.println(String.format("OrderProcessingActor %d %s order received for instrument %s with price %s", order.getOrderId(), order.getOrderType(), order.getInstrument(), order.getPrice()));
    //process order here.
    getSender().tell(String.format("OrderProcessingActor %d %s order processed for instrument %s with price %s", order.getOrderId(), order.getOrderType(), order.getInstrument(), order.getPrice()), getSelf());

is a classic don't-repeat-yourself situation. Make a toString() method on Order:

String toString() {
   return String.format("OrderProcessingActor %d %s order for instrument %s with price %f", orderId, orderType, instrument, price);
}

Then, the prior code can be

    System.out.println(String.format("%s has been received", order));
    //process order here.
    getSender().tell(String.format("%s has been processed", order));
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.