Page History
Tip |
---|
.NET Core 3.1 API 에 Akka.net 탑재하여 기본적인 액터를 생성하여 메시지 전송을 해보겠습니다. |
시작 템플릿
시작 템플릿은 .Net Core 3.1 API 를 사용하였으며, Docker 지원 옵션을 추천합니다. ( 도커 개발환경 지원)
샘플에서 프로젝트명은 AkkaNetCore 로 생성 하였습니다.
라이브러리 추가
Code Block | ||
---|---|---|
| ||
<PackageReference Include="Akka" Version="1.3.17" /> <PackageReference Include="Akka.Cluster" Version="1.3.17" /> <PackageReference Include="Akka.Cluster.Tools" Version="1.3.17" /> <PackageReference Include="Akka.DI.Extensions.DependencyInjection" Version="1.3.2" /> <PackageReference Include="Akka.Logger.NLog" Version="1.3.5" /> <PackageReference Include="NLog.Web.AspNetCore" Version="4.8.1" /> |
...
해당 홈페이지를 통해 셋팅을 하거나 이 프로젝트에서 셋팅된 방법을 참고하세요
Akka Extensions
Akka System및 구성요소(액터,설정) 등을 편리하게 사용하기 위해 사용자 정의 셋팅 파일을 추가합니다.
...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
using System; using System.Collections.Concurrent; using System.IO; using System.Text; using Akka.Actor; using Akka.Configuration; using Microsoft.Extensions.Configuration; using AkkaConfig = Akka.Configuration.Config; namespace AkkaNetCore.Config { public class AkkaLoad { public static ConcurrentDictionary<string, IActorRef> ActorList = new ConcurrentDictionary<string, IActorRef>(); public static void RegisterActor(string name, IActorRef actorRef) { if (ActorList.ContainsKey(name)) throw new Exception("이미 등록된 액터입니다."); ActorList[name] = actorRef; } public static IActorRef ActorSelect(string name) { return ActorList[name]; } public static AkkaConfig Load(string environment, IConfiguration configuration) { if(environment.ToLower()!= "production") { environment = "Development"; } return LoadConfig(environment, "akka{0}.conf", configuration); } private static AkkaConfig LoadConfig(string environment, string configFile, IConfiguration configuration) { string akkaip = configuration.GetSection("akkaip").Value ?? "127.0.0.1"; string akkaport = configuration.GetSection("akkaport").Value ?? "5100"; string akkaseed = configuration.GetSection("akkaseed").Value ?? "127.0.0.1:5100"; string roles = configuration.GetSection("roles").Value ?? "akkanet"; var configFilePath = string.Format(configFile, environment.ToLower() != "production" ? string.Concat(".", environment) : ""); if (File.Exists(configFilePath)) { string config = File.ReadAllText(configFilePath, Encoding.UTF8) .Replace("$akkaport", akkaport) .Replace("$akkaip", akkaip) .Replace("$akkaseed", akkaseed) .Replace("$roles", roles); var akkaConfig = ConfigurationFactory.ParseString(config); Console.WriteLine($"=== AkkaConfig:{configFilePath}\r\n{akkaConfig}\r\n==="); return akkaConfig; } return Akka.Configuration.Config.Empty; } } } |
Config File추가
Code Block | ||
---|---|---|
| ||
akka { loggers = ["Akka.Logger.NLog.NLogLogger, Akka.Logger.NLog"] loglevel = debug } |
...
추가참고 : https://doc.akka.io/docs/akka/2.5/general/configuration.html
기본 액터추가
Code Block | ||||
---|---|---|---|---|
| ||||
using Akka.Actor; using Akka.Event; namespace AkkaNetCore.Actors.Study { public class BasicActor : ReceiveActor { private readonly ILoggingAdapter logger = Context.GetLogger(); public BasicActor() { ReceiveAsync<string>(async msg => { logger.Info($"{msg} 를 전송받았습니다."); }); } } } |
AkkaSystem 탑재가 잘 되었나 확은하는것은 액터를 생성하고 메시지를 보내보는것입니다.
액터 생성
Code Block | ||
---|---|---|
| ||
### 액터 시스템 설정 : ConfigureServices 내에 추가 .... // *** Akka Service Setting var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); var akkaConfig = AkkaLoad.Load(envName, Configuration); var actorSystem = ActorSystem.Create(SystemNameForCluster, akkaConfig); var provider = services.BuildServiceProvider(); actorSystem.UseServiceProvider(provider); services.AddAkka(actorSystem); ### 액터 시스템 구동및 액터 생성 : Configure 내에 추가 app.ApplicationServices.GetService<ILogger>(); var actorSystem = app.ApplicationServices.GetService<ActorSystem>(); // start Akka.NET ActorSystem = actorSystem; //액터생성 오리지널 actorSystem.ActorOf(Props.Create<BasicActor>(),"basic2" //액터생성 커스텀 AkkaLoad.RegisterActor( "basic", actorSystem.ActorOf(Props.Create<BasicActor>(), "basic" )); |
...
AkkaLoad에 의해 커스텀된 생성방법이며, 액터의 참조(IActorRef)를 쉽게 가져오기위해 Dictionary에 등록하는것이 전부입니다.
다양한 DI활용을 통해 ( https://getakka.net/articles/actors/dependency-injection.html) 생성방법을 단순화할수 있으나
액터 객체자체가 Top-level Architecture(https://getakka.net/articles/actors/dependency-injection.html) 로 라이프 사이클의 구조관리가
가능하니 가급적 닷넷 코어의 DI를 액터에 직접 연동시키는 것은 비 권장합니다.
(ex> 액터는 코드변경없이 설정만으로 라운드로빈설정을 하여 x배의 성능을 내는 확장이 가능합니다. 하지만 액터를 싱글톤으로 제약을 둔다고 하면
액터는 확장에 실패할것입니다. 현재 로컬에서 단 하나만 가진다고 하더라도 싱글톤으로 제약을 거는 설계는 바람직 하지 않습니다.
단하나만 존재해도 되는 객체는 액터 시스템이 유일하며, 단하나만 존재해야하는 액터일경우 단하나만 생성하면 됩니다. )
API 에 액터 연결하여 전송하기
Code Block | ||
---|---|---|
| ||
[Route("api/[controller]")] [ApiController] public class ActorTestController : Controller { private readonly IActorRef basicActor; public ActorTestController() { basicActor = AkkaLoad.ActorSelect("basic"); } [HttpPost("/Single/Basic/tell")] public void Printer(string message) { // basicActor 요청한다. basicActor.Tell(message); } ... ## 로그 샘플 [2020-03-06 22:12:43.7874] [Info] [PSMON-ASUS] [AKKA] [ACTOR] [AkkaNetCore.Actors.Study.BasicActor] [11] : 안녕하세요 를 전송받았습니다. |
...