SignalR은 닷넷코어에서 활용가능한 대표적인 웹소켓지원 서버모듈이며
AKKA STREAM기와 연동을 해보겠습니다.
Akka.net의 Alpakka를 활용하였습니다.
STEP 1 - WS CLIENT 추가하기및 참조추가
채팅을 입력하면, 입력한값이 모든 클라이언트에게 뿌리고,
그대로 찍히는 전형적인 브로드 캐스트 Echo Client입니다.
추가 소스 : https://github.com/psmon/AkkaDotModule/tree/master/AkkaDotBootApi/wwwroot
추가 의존
<PackageReference Include="AkkaDotModule.Webnori" Version="1.1.1" /> <PackageReference Include="Akka.Streams.SignalR.AspNetCore" Version="1.0.0-beta3" />
SignalR을 AkkaStream에 연결하는 모듈이며 Alpakka 프로젝트의 일부입니다.
Alpakka를 간단하게 소개하면, 모든 외부 스트림기를 AkkaStream에 연결시도하는 프로젝트이며
모든 스트림이 상호 연동되는 Reactive Stream을 활용하는 특수한 목적의 스트림기라고 보시면 되겠습니다.
- .net : https://alpakka.getakka.net/
- jvm : https://doc.akka.io/docs/alpakka/current/index.html
- reactive stream : https://github.com/reactive-streams
참고로 jvm진영의 Alpakka는 우리가 활용할만한 유용한 오픈진영의 스트림 스택과 대부분 연결이 가능합니다.
닷넷 진영은 계속 확장중에 있는것으로 보입니다.
AkkaStream에 연결함으로 얻는 이점은 마지막에 설명을 하겠습니다.
STEP 2 - Echo Server 추가
using Akka.Streams.Dsl; using Akka.Streams.SignalR.AspNetCore; using Akka.Streams.SignalR.AspNetCore.Internals; using AkkaDotModule.Config; using Microsoft.AspNetCore.SignalR; // Sample : https://github.com/akkadotnet/Alpakka/tree/dev/src/SignalR.AspNetCore namespace AkkaDotBootApi.SignalR { public class EchoHub : StreamHub<EchoStream> { public EchoHub(IStreamDispatcher dispatcher) : base(dispatcher) { } } // AKKA STREAM : https://getakka.net/articles/streams/cookbook.html public class EchoStream : StreamConnector { public EchoStream(IHubClients clients, ConnectionSourceSettings sourceSettings = null, ConnectionSinkSettings sinkSettings = null) : base(clients, sourceSettings, sinkSettings) { Source .Collect(x => x as Received) // Tell everyone .Select(x => Signals.Broadcast(x.Data)) // Or tell everyone else, except one-self // .Select(x => Signals.Broadcast(x.Data, new[] { x.Request.ConnectionId })) // Or just send it back to one-self // .Select(x => Signals.Send(x.Request.ConnectionId, x.Data.Payload)) .To(Sink) .Run(AkkaLoad.Materializer); } } }
STEP3 - SignalR등록및 AkkaStream기에 연결
public void ConfigureServices(.............. // Akka 셋팅 var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); var akkaConfig = AkkaLoad.Load(envName, Configuration); actorSystem = ActorSystem.Create("AkkaDotBootSystem", akkaConfig); services.AddAkka(actorSystem); // Signal R 셋팅 services .AddSingleton(new ConnectionSourceSettings(102400, OverflowStrategy.DropBuffer)) .AddSignalRAkkaStream() .AddSignalR(); public void Configure(.............. app.UseStaticFiles() .UseRouting() .UseEndpoints(endpoints => { endpoints.MapHub<EchoHub>("/echo"); });
SignalR과 AkkaStream을 연결하고, 특정 Endpoint를 ws endpoint로 지정하면 웹소켓 사용준비가 완료됩니다.
AkkaStream에 연결했을때 이점
Source .Collect(x => x as Received) // Tell everyone .Select(x => Signals.Broadcast(x.Data)) // Or tell everyone else, except one-self // .Select(x => Signals.Broadcast(x.Data, new[] { x.Request.ConnectionId })) // Or just send it back to one-self // .Select(x => Signals.Send(x.Request.ConnectionId, x.Data.Payload)) .To(Sink) .Run(AkkaLoad.Materializer);
AkkaStream에서 제공하는 코딩방식이 다소 난해할수 있습니다.
복잡한 Flow 그래프를 화이트보드에 그리고, 코드로 옮겨 적을경우 그래프 모양과 일치를 시킬수 있다란 장점이 있습니다.
AkkaStream자체는 풍부한 Flow제어기능을 제공하지만,SignalR에서 Stream기를 어떻게 활용해야할지는 좀더 연구가 필요할것같습니다.
추가참고 :
- NET AKKA.Stream : https://getakka.net/articles/streams/modularitycomposition.html
- AKKA 스트림설명 추가 참고사이트 : https://sslee05.github.io/blog/2018/05/13/akka-stream-01/
- 리액티브 스트림을 준수하면 상호연동되기 때문에 AKKA스트림일 필요는 없음 : https://engineering.linecorp.com/ko/blog/reactive-streams-with-armeria-1/