protoactor-dotnet icon indicating copy to clipboard operation
protoactor-dotnet copied to clipboard

Durable functions style API

Open rogeralsing opened this issue 3 years ago • 1 comments

One thing that would be very nice to have, is some form of durable workflows similar to durable functions in Azure.

This might be possible to implement using something like this. Pseudo code:

ReceiveAsync(IContext ctx)
{
    if (ctx.Message is Something)
    {
        //Each successful call to Durable().RequestAsync stores the result in a DB with actor own ClusterIdentity + request msg + target ClusterIdentity + response msg
        var x = await ctx.Durable().RequestAsync<Foo>("aaa","bbb", msg);
        var y = await ctx.Durable().RequestAsync<Bar>("xxx","yyy", msg);

        //DO STUFF x,y

        ctx.Durable().Complete() //marks the durable flow as completed, deletes data from DB
    }
}

the Durable extension (plugin) would be able to track requests and responses from and to other actors. and much like durable functions each step in the async request flow could then be re-evaluated without sideeffects until all requests have completed successfully.

Once all requests are done, the code could perform some form of business logic/side effects etc. And then mark the workflow as completed, removing cached values from the database.

rogeralsing avatar Dec 28 '20 11:12 rogeralsing

  Durable Functions:

Durable is an extension, accessible from Cluster and IContext. It piggybacks on RequestAsync behind the scenes.

Starting Workflows:

Args: Function virtual actor id is generated dynamically Kind is function name Message is function start args

//execute
var res = await cluster.Durable().StartFunctionAsync("xyz", message);

If successful, function state is stored in DB Functions do not return a result, only status of started status This is because a function could run for days or weeks. it is a long running async operation.

Workflows calls activities. this could be either normal virtual actor calls. Or, a new special activity abstraction on top of virtual actors.

Workflow implementation:

public class MyWorkflow : DurableFunction
{
    protected override Run(DurableContext context) 
    {
        var args = context.Message; //<-- this is the message passed to the startfunctionasync above
        
        //PID sender do not exist here. we only want to deal with virtual actors (or abstractions) so we can always address them.
        
        //somehow we get Sender as a ClusterIdentity here. not sure how to solve yet. parse PID?


        //these calls must be pure, or seemingly pure
        //result of the call is stored and cached. calling run multiple times would just get result from DB if exists
        var x = await context.RequestAsync("someactor","somekind", somemessage);
        var y = await context.RequestAsync("someOther","fookind", othermessage);
        
        context.Respond(new SomeResult
        {
            Sum = x + y,
        });
    }
}

Activity:

TODO

rogeralsing avatar Jan 01 '21 17:01 rogeralsing