■ 가상 액터/그레인을 사용해 멤버 클러스터에서 스마트 전구를 모델링하는 방법을 보여준다.
▶ TestProject.csproj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> <PackageReference Include="Grpc.Tools" Version="2.58.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="Proto.Actor" Version="1.3.0" /> <PackageReference Include="Proto.Cluster" Version="1.3.0" /> <PackageReference Include="Proto.Cluster.CodeGen" Version="1.3.0" /> <PackageReference Include="Proto.Cluster.TestProvider" Version="1.3.0" /> <PackageReference Include="Proto.Remote" Version="1.3.0" /> </ItemGroup> <ItemGroup> <ProtoGrain Include="Grains.proto" /> </ItemGroup> </Project> |
▶ Grains.proto
1 2 3 4 5 6 7 8 9 10 11 12 13 |
syntax = "proto3"; option csharp_namespace = "TestProject"; import "google/protobuf/empty.proto"; service SmartBulbGrain { rpc TurnOn (google.protobuf.Empty) returns (google.protobuf.Empty); rpc TurnOff (google.protobuf.Empty) returns (google.protobuf.Empty); } |
▶ SmartBulbGrain.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
using Proto; using Proto.Cluster; namespace TestProject; /// <summary> /// 스마트 전구 그레인 /// </summary> public class SmartBulbGrain : SmartBulbGrainBase { //////////////////////////////////////////////////////////////////////////////////////////////////// Enumeration ////////////////////////////////////////////////////////////////////////////////////////// Private #region 스마트 전구 상태 - SmartBulbState /// <summary> /// 스마트 전구 상태 /// </summary> private enum SmartBulbState { Unknown, On, Off } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 클러스터 ID /// </summary> private readonly ClusterIdentity clusterIdentity; /// <summary> /// 스마트 전구 상태 /// </summary> private SmartBulbState state = SmartBulbState.Unknown; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - SmartBulbGrain(context, clusterIdentity) /// <summary> /// 생성자 /// </summary> /// <param name="context">컨텍스트</param> /// <param name="clusterIdentity">클러스터 ID</param> public SmartBulbGrain(IContext context, ClusterIdentity clusterIdentity) : base(context) { this.clusterIdentity = clusterIdentity; Console.WriteLine($"생성 : {this.clusterIdentity.Identity}"); } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 켜기 - TurnOn() /// <summary> /// 켜기 /// </summary> /// <returns>태스크</returns> public override async Task TurnOn() { if(this.state != SmartBulbState.On) { Console.WriteLine($"스마트 전구 켜기 : {this.clusterIdentity.Identity}"); this.state = SmartBulbState.On; } } #endregion #region 끄기 - TurnOff() /// <summary> /// 끄기 /// </summary> /// <returns>태스크</returns> public override async Task TurnOff() { if(this.state != SmartBulbState.Off) { Console.WriteLine($"스마트 전구 끄기 : {this.clusterIdentity.Identity}"); this.state = SmartBulbState.Off; } } #endregion } |
▶ SmartBulbSimulator.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
using Proto; using Proto.Cluster; namespace TestProject; /// <summary> /// 스마트 전구 시뮬레이터 /// </summary> public class SmartBulbSimulator : BackgroundService { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 액터 시스템 /// </summary> private readonly ActorSystem actorSystem; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - SmartBulbSimulator(actorSystem) /// <summary> /// 생성자 /// </summary> /// <param name="actorSystem">액터 시스템</param> public SmartBulbSimulator(ActorSystem actorSystem) { this.actorSystem = actorSystem; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 실행하기 (비동기) - ExecuteAsync(cancellationToken) /// <summary> /// 실행하기 (비동기) /// </summary> /// <param name="cancellationToken">취소 토큰</param> /// <returns>태스크</returns> protected override async Task ExecuteAsync(CancellationToken cancellationToken) { Random random = new Random(DateTime.Now.Millisecond); string[] lightBulbArray = new string[] { "거실1", "거실2", "침실", "부엌" }; while(!cancellationToken.IsCancellationRequested) { string id = lightBulbArray[random.Next(lightBulbArray.Length)]; SmartBulbGrainClient client = this.actorSystem .Cluster() .GetSmartBulbGrain(id); if(random.Next(2) > 0) { await client.TurnOn(cancellationToken); } else { await client.TurnOff(cancellationToken); } await Task.Delay(TimeSpan.FromMilliseconds(500), cancellationToken); } } #endregion } |
▶ ActorSystemConfiguration.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
using Proto; using Proto.Cluster; using Proto.Cluster.Partition; using Proto.Cluster.Testing; using Proto.DependencyInjection; using Proto.Remote.GrpcNet; namespace TestProject; /// <summary> /// 액터 시스템 구성 /// </summary> public static class ActorSystemConfiguration { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 액터 시스템 추가하기 - AddActorSystem(serviceCollection) /// <summary> /// 액터 시스템 추가하기 /// </summary> /// <param name="serviceCollection">서비스 컬렉션</param> public static void AddActorSystem(this IServiceCollection serviceCollection) { serviceCollection.AddSingleton ( provider => { ActorSystemConfig actorSystemConfig = ActorSystemConfig.Setup(); GrpcNetRemoteConfig grpcNetRemoteConfig = GrpcNetRemoteConfig.BindToLocalhost(); ClusterConfig clusterConfig = ClusterConfig.Setup ( clusterName : "TestProject", clusterProvider : new TestProvider(new TestProviderOptions(), new InMemAgent()), identityLookup : new PartitionIdentityLookup() ) .WithClusterKind ( kind : SmartBulbGrainActor.Kind, prop : Props.FromProducer ( () => new SmartBulbGrainActor ( (context, clusterIdentity) => new SmartBulbGrain(context, clusterIdentity) ) ) ); return new ActorSystem(actorSystemConfig) .WithServiceProvider(provider) .WithRemote(grpcNetRemoteConfig) .WithCluster(clusterConfig); } ); } #endregion } |
▶ ActorSystemClusterHostedService.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
using Proto; using Proto.Cluster; namespace TestProject; /// <summary> /// 액터 시스템 클러스터 호스트 서비스 /// </summary> public class ActorSystemClusterHostedService : IHostedService { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 액터 시스템 /// </summary> private readonly ActorSystem actorSystem; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - ActorSystemClusterHostedService(actorSystem) /// <summary> /// 생성자 /// </summary> /// <param name="actorSystem">액터 시스템</param> public ActorSystemClusterHostedService(ActorSystem actorSystem) { this.actorSystem = actorSystem; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 시작하기 (비동기) - StartAsync(cancellationToken) /// <summary> /// 시작하기 (비동기) /// </summary> /// <param name="cancellationToken">취소 토큰</param> /// <returns>태스크</returns> public async Task StartAsync(CancellationToken cancellationToken) { Console.WriteLine("클러스터 멤버를 시작한다."); await this.actorSystem .Cluster() .StartMemberAsync(); } #endregion #region 중단하기 (비동기) - StopAsync(cancellationToken) /// <summary> /// 중단하기 (비동기) /// </summary> /// <param name="cancellationToken">취소 토큰</param> /// <returns>태스크</returns> public async Task StopAsync(CancellationToken cancellationToken) { Console.WriteLine("클러스터 멤버를 중단한다."); await this.actorSystem .Cluster() .ShutdownAsync(); } #endregion } |
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
using Proto; using TestProject; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.Services.AddActorSystem(); builder.Services.AddHostedService<ActorSystemClusterHostedService>(); builder.Services.AddHostedService<SmartBulbSimulator>(); WebApplication application = builder.Build(); ILoggerFactory loggerFactory = application.Services.GetRequiredService<ILoggerFactory>(); Log.SetLoggerFactory(loggerFactory); application.MapGet("/", () => Task.FromResult("안녕하세요, Proto.Cluster!")); application.Run(); |