Akka.NET actor system in ASP.NET
Asked Answered
V

2

13

I created a service with a RESTful API in ASP.NET, hosted in IIS. Inside this service, I would like to create an actor system with Akka.NET.

Upon creating the actor system:

var actorSystem = ActorSystem.Create("myActorSystem");

The following exception is thrown:

A first chance exception of type 'System.InvalidOperationException' occurred in System.Web.dll Additional information: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.

The actor system is inherently a concurrent system with asynchronous messages being exchanged between actors. As explained here, this actor system would not survive IIS taking down the AppDomain, which is probably why the aforementioned exception is thrown.

This article explains how to run background tasks in ASP.NET. However, I don't see how I could use this for my actor system, as I have no control over the lifecycle of background tasks that might be created by Akka.NET.

Is there a way to make this work, or should I abandon the idea of having an actor system in an ASP.NET application?

EDIT: I also saw a question on Stackoverflow about implementing a REST service using Akka. Any advice about a solution similar to the Spray toolkit, but working for Akka.NET would be welcome.

Visceral answered 24/12, 2014 at 9:47 Comment(2)
Actor model sounds cool. But do you really need it?Habitation
I am trying this out as a proof of concept, I don't absolutely need it. A conclusion could be that it would be too complicated.Visceral
H
22

Keep your ActorSystem as a shared property in some static class container - this way you may access it from the rest of your application. Actor system initialization/disposal can be done by:

  • Global.asax - use ActorSystem.Create(...) inside Global.asax Application_Start and dispose it with system.Shutdown() on Application_End.
  • OWIN - create actor system in OWIN's Startup.Configuration method and shut it down by binding to host.OnAppDisposing event (how-to link).

Remember that IIS will startup your web app only after first request and tear it down automatically after some time when it's idle. Therefore make sure, that your deployment script will ping application after publishing and set idle timeout (link) for long enough if you want your Akka actor system to run continuously.

Second option

Separate your Actor System logic and deploy it, for example, as a Windows Service (or Linux deamon). Turn on Akka.Remoting for it and create a proxy client, which will forward all application long-running sensitive tasks to external service. Similar solution is often used for things such as schedulers or event buses, when your application logic must be working continuously.

Hamitic answered 31/12, 2014 at 10:34 Comment(1)
Thanks for your reply Horusiath. I think I will need to go with the second option. The first one is difficult to apply in my case, since the actor system can potentially run very long or continuous tasks.Visceral
E
27

I've used Akka.NET and Akka.Remote inside ASP.NET MVC applications that are doing up to 1000 requests per second on EC2 - so I'll share some of the tips and tricks I used to get it up and running successfully. Had a prototype version that even used Akka.Cluster but ended up not shipping that version.

  • Best place to call ActorSystem.Create is inside Global.asax Application_Start().
  • Hang onto a static reference to the ActorSystem object inside Global.asax itself, using a static field or property. Helps ensure that the ActorSystem itself doesn't get garbage-collected in long-running applications.
  • Create a separate static helper class to initialize any top-level actors your applications needs - i.e. actors at the top of the /user/ hierarchy. This class should also provide actor paths that your ASP.MVC controllers and action methods can use for Tell and Ask operations.

Creating the ActorSystem is a bit of an expensive operation, because lots of system-level stuff gets fired up at once. It's definitely best to do this once at application startup and then just cache the result inside the Application class.

Creating individual actor instances is cheap - you should be able to do this no-problem inside ASP.NET MVC action methods. If you see this error come up again, please let us know what part in the request-handling process this error occurred and with which version of ASP.NET.

Edit: added some updated guidance for how to do this on ASP.NET Core

https://petabridge.com/blog/akkadotnet-aspnetcore/

Enterogastrone answered 25/12, 2014 at 8:12 Comment(3)
Thanks for your reply Aaron. As explained on this site, ASP.NET could tear down your AppDomain at any time, therefore aborting any background execution in your application. What would happen to your actor system when that happens?Visceral
In all of these scenarios, Akka.NET is running inside the ASP.NET AppDomain - so in the event of any of the scenarios Haack outlines, your web app gets recycled along with your actor system(web.config edit, IIS process recycle, etc...) Depending on your hosting environment, you can control all of these through IIS and machine.config settings. Regardless though, the ActorSystem will still be active at the same time as your web application - there's nothing that will go through and kill off your ActorSystem but leave the ASP.NET app intact following what I oultined above.Enterogastrone
the actor system will be active at the same time as my web application, yes. What I would like to avoid is that this actor system is stopped without warning upon a recycle, with still active actors and non-empty message queues.Visceral
H
22

Keep your ActorSystem as a shared property in some static class container - this way you may access it from the rest of your application. Actor system initialization/disposal can be done by:

  • Global.asax - use ActorSystem.Create(...) inside Global.asax Application_Start and dispose it with system.Shutdown() on Application_End.
  • OWIN - create actor system in OWIN's Startup.Configuration method and shut it down by binding to host.OnAppDisposing event (how-to link).

Remember that IIS will startup your web app only after first request and tear it down automatically after some time when it's idle. Therefore make sure, that your deployment script will ping application after publishing and set idle timeout (link) for long enough if you want your Akka actor system to run continuously.

Second option

Separate your Actor System logic and deploy it, for example, as a Windows Service (or Linux deamon). Turn on Akka.Remoting for it and create a proxy client, which will forward all application long-running sensitive tasks to external service. Similar solution is often used for things such as schedulers or event buses, when your application logic must be working continuously.

Hamitic answered 31/12, 2014 at 10:34 Comment(1)
Thanks for your reply Horusiath. I think I will need to go with the second option. The first one is difficult to apply in my case, since the actor system can potentially run very long or continuous tasks.Visceral

© 2022 - 2024 — McMap. All rights reserved.