Skip to content

Commit db826ec

Browse files
committed
Actor review
1 parent 3623cfc commit db826ec

File tree

1 file changed

+19
-19
lines changed
  • docs/architecture/dapr-for-net-developers

1 file changed

+19
-19
lines changed

docs/architecture/dapr-for-net-developers/actors.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: The Dapr actors building block
33
description: A deep dive into the Dapr actors building block and how to apply it
44
author: amolenk
5-
ms.date: 05/30/2021
5+
ms.date: 06/22/2021
66
---
77

88
# The Dapr actors building block
@@ -96,7 +96,7 @@ public int Increment()
9696
{
9797
int newValue;
9898

99-
lock (this.lockObject)
99+
lock (_lockObject)
100100
{
101101
var currentValue = GetValue();
102102
newValue = currentValue + 1;
@@ -236,15 +236,15 @@ Let's now implement the `IncrementScoreAsync` method of the interface:
236236
```csharp
237237
public Task<int> IncrementScoreAsync()
238238
{
239-
return this.StateManager.AddOrUpdateStateAsync(
239+
return StateManager.AddOrUpdateStateAsync(
240240
"score",
241241
1,
242242
(key, currentScore) => currentScore + 1
243243
);
244244
}
245245
```
246246

247-
In the snippet above, a single call to `StateManager.AddOrUpdateStateAsync` provides the full implementation for the `IncrementAsync` method. The `AddOrUpdateStateAsync` method takes three arguments:
247+
In the snippet above, a single call to `StateManager.AddOrUpdateStateAsync` provides the full implementation for the `IncrementScoreAsync` method. The `AddOrUpdateStateAsync` method takes three arguments:
248248

249249
1. The key of the state to update.
250250
1. The value to write if no score is stored in the state store yet.
@@ -255,7 +255,7 @@ The `GetScoreAsync` implementation reads the current score from the state store
255255
```csharp
256256
public async Task<int> GetScoreAsync()
257257
{
258-
var scoreValue = await this.StateManager.TryGetStateAsync<int>("score");
258+
var scoreValue = await StateManager.TryGetStateAsync<int>("score");
259259
if (scoreValue.HasValue)
260260
{
261261
return scoreValue.Value;
@@ -288,7 +288,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
288288
The actors endpoints are necessary because the Dapr sidecar calls the application to host and interact with actor instances.
289289

290290
> [!IMPORTANT]
291-
> By default, a generated `Startup` class contains an `app.UseHttpsRedirection` call to redirect client to the HTTPS endpoint. This will not work with actors and must be removed. By design, a Dapr sidecar send requests over unencrypted HTTP by default. The HTTPS middleware will block these requests when enabled.
291+
> By default, a generated `Startup` class contains an `app.UseHttpsRedirection` call to redirect client to the HTTPS endpoint. This will not work with actors and must be removed. By design, a Dapr sidecar sends requests over unencrypted HTTP by default. The HTTPS middleware will block these requests when enabled.
292292

293293
The `Startup` class is also the place to register the specific actor types. In the example below, `ConfigureServices` registers the `ScoreActor` using `services.AddActors`:
294294

@@ -307,7 +307,7 @@ public void ConfigureServices(IServiceCollection services)
307307
At this point, the ASP.NET Core service is ready to host the `ScoreActor` and accept incoming requests. Client applications use actor proxies to invoke operations on actors. The following example shows how a console client application invokes the `IncrementScoreAsync` operation on a `ScoreActor` instance:
308308

309309
```csharp
310-
static async Task Main(string[] args)
310+
static async Task MainAsync(string[] args)
311311
{
312312
var actorId = new ActorId("scoreActor1");
313313
@@ -319,7 +319,7 @@ static async Task Main(string[] args)
319319
}
320320
```
321321

322-
The above example uses the `Dapr.Actors` package to call the actor service. To invoke an operation on an actor, you need to be able to address it. You'll need two parts for this:
322+
The above example uses the [`Dapr.Actors`](https://www.nuget.org/packages/Dapr.Actors) package to call the actor service. To invoke an operation on an actor, you need to be able to address it. You'll need two parts for this:
323323

324324
1. The **actor type** uniquely identifies the actor implementation across the whole application. By default, the actor type is the name of the implementation class (without namespace). You can customize the actor type by adding an `ActorAttribute` to the implementation class and setting its `TypeName` property.
325325
1. The `ActorId` uniquely identifies an instance of an actor type. You can also use this class to generate a random actor id by calling `ActorId.CreateRandom`.
@@ -366,7 +366,7 @@ public class ScoreController : ControllerBase
366366
}
367367
368368
[HttpPut("{scoreId}")]
369-
public Task<int> Increment(string scoreId)
369+
public Task<int> IncrementAsync(string scoreId)
370370
{
371371
var scoreActor = _actorProxyFactory.CreateActorProxy<IScoreActor>(
372372
new ActorId(scoreId),
@@ -414,7 +414,7 @@ You create weakly-typed proxies in a similar way to strongly-typed proxies. Inst
414414

415415
```csharp
416416
[HttpPut("{scoreId}")]
417-
public Task<int> Increment(string scoreId)
417+
public Task<int> IncrementAsync(string scoreId)
418418
{
419419
var scoreActor = _actorProxyFactory.CreateActorProxy(
420420
new ActorId(scoreId),
@@ -445,11 +445,11 @@ public class TimerActor : Actor, ITimerActor
445445
TimeSpan.FromSeconds(3));
446446
}
447447
448-
public Task TimerCallback(byte[] state)
448+
public Task TimerCallbackAsync(byte[] state)
449449
{
450450
var text = Encoding.UTF8.GetString(state);
451451
452-
this.Logger.LogInformation($"Timer fired: {text}");
452+
Logger.LogInformation($"Timer fired: {text}");
453453
454454
return Task.CompletedTask;
455455
}
@@ -464,7 +464,7 @@ The `StartTimerAsync` method calls `RegisterTimerAsync` to schedule the timer. `
464464
1. The amount of time to wait before the callback method is first invoked.
465465
1. The time interval between callback method invocations. You can specify `TimeSpan.FromMilliseconds(-1)` to disable periodic signaling.
466466

467-
The `TimerCallback` method receives the user state in binary form. In the example, the callback decodes the state back to a `string` before writing it to the log.
467+
The `TimerCallbackAsync` method receives the user state in binary form. In the example, the callback decodes the state back to a `string` before writing it to the log.
468468

469469
Timers can be stopped by calling `UnregisterTimerAsync`:
470470

@@ -526,7 +526,7 @@ public class ReminderActor : Actor, IReminderActor, IRemindable
526526
{
527527
var text = Encoding.UTF8.GetString(state);
528528
529-
this.Logger.LogInformation($"Don't forget: {text}");
529+
Logger.LogInformation($"Don't forget: {text}");
530530
}
531531
532532
return Task.CompletedTask;
@@ -556,7 +556,7 @@ public interface IVehicleActor : IActor
556556
}
557557
```
558558

559-
The (simulated) entry cameras call the `RegisterEntry` method when a new vehicle is first detected in the lane. The only responsibility of this method is storing the entry timestamp in the actor state:
559+
The (simulated) entry cameras call the `RegisterEntryAsync` method when a new vehicle is first detected in the lane. The only responsibility of this method is storing the entry timestamp in the actor state:
560560

561561
```csharp
562562
var vehicleState = new VehicleState
@@ -567,17 +567,17 @@ var vehicleState = new VehicleState
567567
await StateManager.SetStateAsync("VehicleState", vehicleState);
568568
```
569569

570-
When the vehicle reaches the end of the speed camera zone, the exit camera calls the `RegisterExit` method. The `RegisterExit` method first gets the current states and updates it to include the exit timestamp:
570+
When the vehicle reaches the end of the speed camera zone, the exit camera calls the `RegisterExitAsync` method. The `RegisterExitAsync` method first gets the current states and updates it to include the exit timestamp:
571571

572572
```csharp
573573
var vehicleState = await StateManager.GetStateAsync<VehicleState>("VehicleState");
574574
vehicleState.ExitTimestamp = msg.Timestamp;
575575
```
576576

577577
> [!NOTE]
578-
> The code above currently assumes that a `VehicleState` instance has already been saved by the `RegisterEntry` method. The code could be improved by first checking to make sure the state exists. Thanks to the turn-based access model, no explicit locks are required in the code.
578+
> The code above currently assumes that a `VehicleState` instance has already been saved by the `RegisterEntryAsync` method. The code could be improved by first checking to make sure the state exists. Thanks to the turn-based access model, no explicit locks are required in the code.
579579

580-
After the state is updated, the `RegisterExit` method checks if the vehicle was driving too fast. If it was, the actor publishes a message to the `collectfine` pub/sub topic:
580+
After the state is updated, the `RegisterExitAsync` method checks if the vehicle was driving too fast. If it was, the actor publishes a message to the `collectfine` pub/sub topic:
581581

582582
```csharp
583583
int violation = _speedingViolationCalculator.DetermineSpeedingViolationInKmh(
@@ -621,7 +621,7 @@ The actor based implementation no longer uses the Dapr state management building
621621

622622
## Summary
623623

624-
The Dapr actors building block makes it easier to write correct concurrent systems. Actors are small units of state and logic. They use a turn-based access model which saves you from having to write error-prone thread-safe code. Actors are created implicitly and are silently unloaded from memory when no operations are performed. Any state stored in the actor is automatically persisted and loaded when the actor is reactivated. Actor model implementations are typically created for a specific language or platform. With the Dapr actors building block however, you can leverage the actor model from any language or platform.
624+
The Dapr actors building block makes it easier to write correct concurrent systems. Actors are small units of state and logic. They use a turn-based access model which saves you from having to use locking mechanisms to write thread-safe code. Actors are created implicitly and are silently unloaded from memory when no operations are performed. Any state stored in the actor is automatically persisted and loaded when the actor is reactivated. Actor model implementations are typically created for a specific language or platform. With the Dapr actors building block however, you can leverage the actor model from any language or platform.
625625

626626
Actors support timers and reminders to schedule future work. Timers do not reset the idle timer and will allow the actor to be deactivated when no other operations are performed. Reminders do reset the idle timer and are also persisted automatically. Both timers and reminders respect the turn-based access model, making sure that no other operations can execute while the timer/reminder events are handled.
627627

0 commit comments

Comments
 (0)