快速入门:Actors
开始使用 Dapr 的 Actors 构建块
让我们来看看Dapr的Actors构建块。 在这个快速入门中,您将运行一个智能设备微服务和一个简单的控制台客户端,以演示 Dapr Actors 中的有状态对象模式。
当前,您可以使用.NET SDK来体验 actor 的快速入门。
作为 .NET actors 快速入门的一个简要概述:
- 使用一个
SmartDevice.Service
微服务,您可以托管:- 两个
SmartDectectorActor
烟雾报警对象 - 一个
ControllerActor
对象,用于命令和控制智能设备
- 两个
- 使用一个
SmartDevice.Client
控制台应用程序,客户端应用程序与每个actor或控制器进行交互,以执行聚合操作。 - 这
SmartDevice.Interfaces
包含服务和客户端应用使用的共享接口和数据类型。
先决条件
对于此示例,您将需要:
第1步:设置环境
git clone https://github.com/dapr/quickstarts.git
第2步:运行服务应用
在一个新的终端窗口中,导航到 actors/csharp/sdk/service
目录并恢复依赖项:
cd actors/csharp/sdk/service
dotnet build
运行SmartDevice.Service
,它将启动服务本身和Dapr sidecar:
dapr run --app-id actorservice --app-port 5001 --dapr-http-port 3500 --resources-path ../../../resources -- dotnet run --urls=http://localhost:5001/
预期输出:
== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
== APP == Request starting HTTP/1.1 GET http://127.0.0.1:5001/healthz - -
== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
== APP == Executing endpoint 'Dapr Actors Health Check'
== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
== APP == Executed endpoint 'Dapr Actors Health Check'
== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
== APP == Request finished HTTP/1.1 GET http://127.0.0.1:5001/healthz - - - 200 - text/plain 5.2599ms
步骤 3:运行客户端应用程序
在新的终端窗口中,导航到 actors/csharp/sdk/client
目录并安装依赖项:
cd ./actors/csharp/sdk/client
dotnet build
运行 SmartDevice.Client
应用程序:
dapr run --app-id actorclient -- dotnet run
预期输出:
== APP == Startup up...
== APP == Calling SetDataAsync on SmokeDetectorActor:1...
== APP == Got response: Success
== APP == Calling GetDataAsync on SmokeDetectorActor:1...
== APP == Device 1 state: Location: First Floor, Status: Ready
== APP == Calling SetDataAsync on SmokeDetectorActor:2...
== APP == Got response: Success
== APP == Calling GetDataAsync on SmokeDetectorActor:2...
== APP == Device 2 state: Location: Second Floor, Status: Ready
== APP == Registering the IDs of both Devices...
== APP == Registered devices: 1, 2
== APP == Detecting smoke on Device 1...
== APP == Device 1 state: Location: First Floor, Status: Alarm
== APP == Device 2 state: Location: Second Floor, Status: Alarm
== APP == Sleeping for 16 seconds before checking status again to see reminders fire and clear alarms
== APP == Device 1 state: Location: First Floor, Status: Ready
== APP == Device 2 state: Location: Second Floor, Status: Ready
(可选)第4步:在Zipkin中查看
如果您在计算机上本地为 Dapr 配置了 Zipkin,您可以在 Zipkin Web UI 中查看 actor 与客户端的交互(通常在 http://localhost:9411/zipkin/
)。
发生了什么?
当您运行客户端应用程序时,会发生几件事情:
两个
SmartDetectorActor
actors 在客户端应用程序中被创建,并且使用对象状态进行初始化:ActorProxy.Create<ISmartDevice>(actorId, actorType)
proxySmartDevice.SetDataAsync(data)
这些对象是可重入的并且保存状态,正如
proxySmartDevice.GetDataAsync()
所示。// Actor Ids and types
var deviceId1 = "1";
var deviceId2 = "2";
var smokeDetectorActorType = "SmokeDetectorActor";
var controllerActorType = "ControllerActor";
Console.WriteLine("Startup up...");
// An ActorId uniquely identifies the first actor instance for the first device
var deviceActorId1 = new ActorId(deviceId1);
// Create a new instance of the data class that will be stored in the first actor
var deviceData1 = new SmartDeviceData(){
Location = "First Floor",
Status = "Ready",
};
// Create the local proxy by using the same interface that the service implements.
var proxySmartDevice1 = ActorProxy.Create<ISmartDevice>(deviceActorId1, smokeDetectorActorType);
// Now you can use the actor interface to call the actor's methods.
Console.WriteLine($"Calling SetDataAsync on {smokeDetectorActorType}:{deviceActorId1}...");
var setDataResponse1 = await proxySmartDevice1.SetDataAsync(deviceData1);
Console.WriteLine($"Got response: {setDataResponse1}");
Console.WriteLine($"Calling GetDataAsync on {smokeDetectorActorType}:{deviceActorId1}...");
var storedDeviceData1 = await proxySmartDevice1.GetDataAsync();
Console.WriteLine($"Device 1 state: {storedDeviceData1}");
// Create a second actor for second device
var deviceActorId2 = new ActorId(deviceId2);
// Create a new instance of the data class that will be stored in the first actor
var deviceData2 = new SmartDeviceData(){
Location = "Second Floor",
Status = "Ready",
};
// Create the local proxy by using the same interface that the service implements.
var proxySmartDevice2 = ActorProxy.Create<ISmartDevice>(deviceActorId2, smokeDetectorActorType);
// Now you can use the actor interface to call the second actor's methods.
Console.WriteLine($"Calling SetDataAsync on {smokeDetectorActorType}:{deviceActorId2}...");
var setDataResponse2 = await proxySmartDevice2.SetDataAsync(deviceData2);
Console.WriteLine($"Got response: {setDataResponse2}");
Console.WriteLine($"Calling GetDataAsync on {smokeDetectorActorType}:{deviceActorId2}...");
var storedDeviceData2 = await proxySmartDevice2.GetDataAsync();
Console.WriteLine($"Device 2 state: {storedDeviceData2}");
调用SmartDetectorActor 1的DetectSmokeAsync方法。
public async Task DetectSmokeAsync()
{
var controllerActorId = new ActorId("controller");
var controllerActorType = "ControllerActor";
var controllerProxy = ProxyFactory.CreateActorProxy<IController>(controllerActorId, controllerActorType);
await controllerProxy.TriggerAlarmForAllDetectors();
}
调用ControllerActor的TriggerAlarmForAllDetectors方法。 当检测到烟雾时,
ControllerActor
会内部触发所有警报public async Task TriggerAlarmForAllDetectors()
{
var deviceIds = await ListRegisteredDeviceIdsAsync();
foreach (var deviceId in deviceIds)
{
var actorId = new ActorId(deviceId);
var proxySmartDevice = ProxyFactory.CreateActorProxy<ISmartDevice>(actorId, "SmokeDetectorActor");
await proxySmartDevice.SoundAlarm();
}
// Register a reminder to refresh and clear alarm state every 15 seconds
await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
}
控制台打印一条消息,指示检测到烟雾。
// Smoke is detected on device 1 that triggers an alarm on all devices.
Console.WriteLine($"Detecting smoke on Device 1...");
proxySmartDevice1 = ActorProxy.Create<ISmartDevice>(deviceActorId1, smokeDetectorActorType);
await proxySmartDevice1.DetectSmokeAsync();
调用 SmartDetectorActor 1 和
2
的 SoundAlarm 方法。storedDeviceData1 = await proxySmartDevice1.GetDataAsync();
Console.WriteLine($"Device 1 state: {storedDeviceData1}");
storedDeviceData2 = await proxySmartDevice2.GetDataAsync();
Console.WriteLine($"Device 2 state: {storedDeviceData2}");
ControllerActor
还会使用RegisterReminderAsync
创建一个持久的提醒,在15秒后调用ClearAlarm
。// Register a reminder to refresh and clear alarm state every 15 seconds
await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
对于示例的完整上下文,请查看以下代码:
- SmartDetectorActor.cs: 实现了智能设备 actor
- ControllerActor.cs: 实现了管理所有设备的控制器 actor
- ISmartDevice: 每个
SmartDetectorActor
的方法定义和共享数据类型 - IController:
ControllerActor
的方法定义和共享数据类型
告诉我们您的想法
我们一直在努力改进我们的快速入门示例,并重视您的反馈。 您觉得此快速入门有帮助吗? 您有改进的建议吗?
加入我们的discord频道参与讨论。
下一步
了解更多关于Actor构建块