1
votes

We are in the process of adding akka.net actors to part of a legacy system.

The basic idea is that a message comes in from an external system, it is handed off to a logic that is managed by akka.net actors which then talk to legacy components that do things like save data to the database.

The legacy code relies on the fact that a userId is set in the CallContext, which it can then retrieve before doing database writes (to store things like "CreatedBy" and "LastModifiedBy"). It seems clear that the CallContext will not be available once the message is passed through the actor system.

This seems like it would be a common problem/requirement, but I've been unable to find this question via google or looking through the akka/akka.net discussion groups.

Is there a concept of a contextual wrapper/envelope in akka.net, or is my only option to make the passing of contextual information an explicit part of the message?

2

2 Answers

4
votes

Since your message may be possibly passed across actor system boundaries, the best option here seems to be wrapping CallContext and message to be passed, and load it on message arrival to one of the actor's fields. Here is the example code using AroundReceive method:

public struct Wrapper {
    public readonly CallContext CallContext;
    public readonly object Message;
    ...
}

public abstract class ContextualActor : ReceiveActor {
    protected CallContext CallContext;
    protected override bool AroundReceive(Receive receive, object message) {
        if (message is Wrapper) {
            var wrapped = (Wrapper)message;
            CallContext = wrapped.CallContext;
            return base.AroundReceive(receive, wrapped.Message);
        }
        else return base.AroundReceive(receive, message);
    }

    public void Send(IActorRef aref, object message) => 
        aref.Tell(new Wrapper(CallContext, message))
}

This way, call context will be loaded already, when the message hits the receive method of an actor. Remember that for this, CallContext must be serializable and immutable, otherwise it won't be safe and work properly.

1
votes

Akka.NET is currently not very ExecutionContext friendly. The ThreadPoolDispatcher is using ThreadPool.UnsafeQueueUserWorkItem if the AppDomain is in full trust, so the CallContext will not flow across actors.

However, if you consume the ActorSystem with Ask, the ExecutionContext will be captured by the TPL and restored in the Task's continuation.