Edited to update answer.
It sounds like we have a repository that contains a collection of cars, and each car can have a VIN or REG number (or serial number, or chassis number... things that uniquely identify a car).
ID | VIN | REG
car1 | ABC | 123
car2 | DEF | 456
We also have a persistent CarActor
that encapsulates state and logic for a car.
public class CarActor : PersistentReceiveActor
{
string _id;
public override string PersistenceId { get { return _id; } }
public CarActor(string id)
{
_id = id;
}
public static Props Props(string id)
{
return Akka.Actor.Props.Create(() => new CarActor(id));
}
}
As we need a single "true name" to use as the actor name/persistence
ID when recreating an actor, these "lookups/references" are themselves
actors, named after their key, persisting only the ID of the actor
they reference.
Does this seem like the right way to do it? It seems like a lot of
actors which aren't really actors, just proxies.
To simplify things, we could define a message that encapsulates the various ID numbers a car can be identified with. This message can then be passed to our Actor system for processing.
public class CarCommand
{
public string Vin { get; private set; }
public string Reg { get; private set; }
}
Best practice is to have a supervisor or router actor that is responsible for a domain of entities and elects to represent each entity as its own actor. This supervisor can receive a CarCommand
message, look up the ID of the car by VIN or REG, and find/create a child actor to process the message.
public class CarSupervisor : ReceiveActor
{
//in reality this would be a repository e.g. a DB context... it would
//be even better if this was handled in another Actor that this Actor
//has access to
readonly IEnumerable<Cars> _cars;
public CarSupervisor(IEnumerable<Cars> cars)
{
_cars = cars;
Receive<CarCommand>(command =>
{
//find a car by VIN or REG or other variable
var car = _cars.First(c => c.VIN == command.VIN);
//see if any child actors have been created for this car instance
var child = Context.Child(car.Id);
//if we don't have an incarnation yet, create one
if (Equals(child, ActorRefs.Nobody))
child = Context.ActorOf(CarActor.Props(car.Id), car.Id));
//tell the child to process the message
child.Forward(command);
});
}
}