Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A minimal actor framework, part 2

DZone's Guide to

A minimal actor framework, part 2

·
Free Resource

Yesterday I introduced a very minimal actor “framework”, and I noted that while it was very simple, it wasn’t a very good one. The major problems in that implementation are:

  • No considerations for errors
  • No considerations for async operations

The first one seems obvious, but what about the second one, how can we not consider async operations in an actor framework?

Well, the answer to that is quite simple, our actor framework assumed that we were always going to execute synchronously. That isn’t going to work if there is a need to do things like async IO.

As it happened, that is precisely what I had in mind for this code, so I wrote this:

public class Actor<TState>
{
    public TState State { get; set; }

    private readonly ConcurrentQueue<Func<TState, Task>> actions = new ConcurrentQueue<Func<TState, Task>>();
    private Task activeTask;

    public void Act(Func<TState, Task> action)
    {
        actions.Enqueue(action);

        lock(this)
        {
            if (activeTask != null) 
                return;
            activeTask = Task.Factory.StartNew(ExecuteActions);
        }
    }

    public event EventHandler<UnhandledExceptionEventArgs> OnError;

    private void InvokeOnError(UnhandledExceptionEventArgs e)
    {
        var handler = OnError;
        if (handler == null) 
            throw new InvalidOperationException("An error was raised for an actor with no error handling capabilities");
        handler(this, e);
    }

    private void ExecuteActions()
    {
        Func<TState, Task> func;
        if (actions.TryDequeue(out func))
        {
            func(State)
                .ContinueWith(x =>
                {
                    if (x.Exception != null)
                    {
                        InvokeOnError(new UnhandledExceptionEventArgs(x.Exception, false));
                        return;
                    }
                    ExecuteActions();
                });
            return;
        }
        lock(this)
        {
            activeTask = null;
        }
    }
}

Thoughts?

Topics:

Published at DZone with permission of Oren Eini, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}