more changes per mark

Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>
This commit is contained in:
Hannah Hunter 2023-03-30 17:11:28 -04:00
parent 333f3ac771
commit fe468ff658
7 changed files with 500 additions and 343 deletions

View File

@ -2,31 +2,37 @@
type: docs
title: "How-to: Enable and use actor reentrancy in Dapr"
linkTitle: "How-To: Actor reentrancy"
weight: 50
weight: 70
description: Learn more about actor reentrancy
---
## Actor reentrancy
A core tenet of the virtual actor pattern is the single-threaded nature of actor execution. Without reentrancy, the Dapr runtime locks on all actor requests, even those that are in the same call chain. A second request could not start until the first had completed. This means an actor cannot call itself, or have another actor call into it even if it is part of the same chain. Reentrancy solves this by allowing requests from the same chain, or context, to re-enter into an already locked actor. This is especially useful in scenarios where an actor wants to call a method on itself or when actors are used in workflows where other actors are used to perform work, and they then call back onto the coordinating actor. Examples of chains that reentrancy allows are shown below:
A core tenet of the [virtual actor pattern](https://www.microsoft.com/research/project/orleans-virtual-actors/) is the single-threaded nature of actor execution. Without reentrancy, the Dapr runtime locks on all actor requests. A second request wouldn't be able to start until the first had completed. This means an actor cannot call itself, or have another actor call into it, even if it's part of the same call chain.
Reentrancy solves this by allowing requests from the same chain, or context, to re-enter into an already locked actor. This proves useful in scenarios where:
- An actor wants to call a method on itself
- Actors are used in workflows to perform work, then call back onto the coordinating actor.
Examples of chains that reentrancy allows are shown below:
```
Actor A -> Actor A
ActorA -> Actor B -> Actor A
```
With reentrancy, there can be more complex actor calls without sacrificing the single-threaded behavior of virtual actors.
With reentrancy, you can perform more complex actor calls, without sacrificing the single-threaded behavior of virtual actors.
<img src="/images/actor-reentrancy.png" width=1000 height=500 alt="Diagram showing reentrancy for a coordinator workflow actor calling worker actors or an actor calling an method on itself">
The `maxStackDepth` parameter sets a value that controls how many reentrant calls be made to the same actor. By default this is set to 32, which is more than sufficient in most cases.
The `maxStackDepth` parameter sets a value that controls how many reentrant calls can be made to the same actor. By default, this is set to **32**, which is more than sufficient in most cases.
## Enable Actor Reentrancy with Actor Configuration
## Configure the actor runtime to enable reentrancy
The actor that will be reentrant must provide configuration to use reentrancy. This is done by the actor's endpoint for `GET /dapr/config`, similar to other actor configuration elements.
The reentrant actor must provide the appropriate configuration. This is done by the actor's endpoint for `GET /dapr/config`, similar to other actor configuration elements.
{{< tabs Dotnet Python Go >}}
{{< tabs ".NET" JavaScript Python Java Go >}}
{{% codetab %}}
<!--dotnet-->
```csharp
public class Startup
@ -50,6 +56,27 @@ public class Startup
{{% /codetab %}}
{{% codetab %}}
<!--javascript-->
```js
import { CommunicationProtocolEnum, DaprClient, DaprServer } from "@dapr/dapr";
// Configure the actor runtime with the DaprClientOptions.
const clientOptions = {
actor: {
reentrancy: {
enabled: true,
maxStackDepth: 32,
},
},
};
```
{{% /codetab %}}
{{% codetab %}}
<!--python-->
```python
from fastapi import FastAPI
from dapr.ext.fastapi import DaprActor
@ -75,6 +102,16 @@ def do_something_reentrant():
```
{{% /codetab %}}
{{% codetab %}}
<!--java-->
```java
```
{{% /codetab %}}
{{% codetab %}}
Here is a snippet of an actor written in Golang providing the reentrancy configuration via the HTTP API. Reentrancy has not yet been included into the Go SDK.
@ -105,10 +142,11 @@ func configHandler(w http.ResponseWriter, r *http.Request) {
}
```
### Handling reentrant requests
### Handle reentrant requests
The key to a reentrant request is the `Dapr-Reentrancy-Id` header. The value of this header is used to match requests to their call chain and allow them to bypass the actor's lock.
The header is generated by the Dapr runtime for any actor request that has a reentrant config specified. Once it is generated, it is used to lock the actor and must be passed to all future requests. Below are the snippets of code from an actor handling this:
The header is generated by the Dapr runtime for any actor request that has a reentrant config specified. Once it is generated, it is used to lock the actor and must be passed to all future requests. Below is an example of an actor handling a reentrant request:
```go
func reentrantCallHandler(w http.ResponseWriter, r *http.Request) {
@ -134,7 +172,19 @@ func reentrantCallHandler(w http.ResponseWriter, r *http.Request) {
{{< /tabs >}}
## Demo
Watch this [video](https://www.youtube.com/watch?v=QADHQ5v-gww&list=PLcip_LgkYwzuF-OV6zKRADoiBvUvGhkao&t=674s) on how to use actor reentrancy.
<div class="embed-responsive embed-responsive-16by9">
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/QADHQ5v-gww?start=674" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
## Next steps
{{< button text="Actors in the Dapr SDKs" page="developing-applications/sdks/#sdk-languages" >}}
## Related links
- [Actors API reference]({{< ref actors_api.md >}})
- [Actors overview]({{< ref actors-overview.md >}})

View File

@ -100,8 +100,4 @@ Learn more about actor types and ids specific to each SDK:
- [Actors API reference]({{< ref actors_api.md >}})
- [Actors overview]({{< ref actors-overview.md >}})
- [How to: Use virtual actors in Dapr]({{< ref howto-actors.md >}})
- Actors using the:
- [.NET SDK]({{< ref dotnet-actors.md >}})
- [Python SDK]({{< ref python-actor.md >}})
- [Java SDK]({{< ref js-actors.md >}})
- [How to: Use virtual actors in Dapr]({{< ref howto-actors.md >}})

View File

@ -105,24 +105,9 @@ The functionality of timers and reminders is very similar. The main difference i
This distinction allows users to trade off between light-weight but stateless timers vs. more resource-demanding but stateful reminders.
- [Learn more about actor timers.]({{< ref "actors-features-concepts.md#timers" >}})
- [Learn more about actor timers.]({{< ref "actors-features-concepts.md#reminders" >}})
- [Learn more about actor reminders.]({{< ref "actors-features-concepts.md#reminders" >}})
- [Learn more about timer and reminder error handling and failover.]({{< ref "actors-features-concepts.md#timers-and-reminders-error-handling" >}})
## Try out actors
### Tutorials
Want to put the Dapr actors API to the test? Walk through the following quickstart and tutorials to see actors in action:
| Quickstart/tutorial | Description |
| ------------------- | ----------- |
| [Actors tutorial](todo) | todo |
### Start using actors directly in your app
Want to skip the quickstarts? Not a problem. You can try out the actors building block directly in your application. After [Dapr is installed]({{< ref "getting-started/_index.md" >}}), you can begin using the actors API starting with [the how-to guide]({{< ref howto-actors.md >}}).
## Next steps
{{< button text="Actors features and concepts >>" page="actors-features-concepts.md" >}}
@ -130,7 +115,4 @@ Want to skip the quickstarts? Not a problem. You can try out the actors building
## Related links
- [Actors API reference]({{< ref actors_api.md >}})
- Actors using the:
- [.NET SDK]({{< ref dotnet-actors.md >}})
- [Python SDK]({{< ref python-actor.md >}})
- [Java SDK]({{< ref js-actors.md >}})
- Refer to the [Dapr SDK documentation and examples]({{< ref "developing-applications/sdks/#sdk-languages" >}}).

View File

@ -0,0 +1,206 @@
---
type: docs
title: "Actor runtime configuration parameters"
linkTitle: "Runtime configuration"
weight: 40
description: Modify the default Dapr actor runtime configuration behavior
---
You can modify the default Dapr actor runtime behavior using the following configuration parameters.
| Parameter | Description | Default |
| --------- | ----------- | ------- |
| `entities` | The actor types supported by this host. | N/A |
| `actorIdleTimeout` | The timeout before deactivating an idle actor. Checks for timeouts occur every `actorScanInterval` interval. | 60 minutes |
| `actorScanInterval` | The duration which specifies how often to scan for actors to deactivate idle actors. Actors that have been idle longer than actor_idle_timeout will be deactivated. | 30 seconds |
| `drainOngoingCallTimeout` | The duration when in the process of draining rebalanced actors. This specifies the timeout for the current active actor method to finish. If there is no current actor method call, this is ignored. | 60 seconds |
| `drainRebalancedActors` | If true, Dapr will wait for `drainOngoingCallTimeout` duration to allow a current actor call to complete before trying to deactivate an actor. | true |
| `reentrancy` (`ActorReentrancyConfig`) | Configure the reentrancy behavior for an actor. If not provided, reentrancy is disabled. | disabled, false |
| `remindersStoragePartitions` | Configure the number of partitions for actor's reminders. If not provided, all reminders are saved as a single record in actor's state store. | 0 |
| `entitiesConfig` | Configure each actor type individually with an array of configurations. Any entity specified in the individual entity configurations must also be specified in the top level `entities` field. | N/A |
## Examples
{{< tabs ".NET" JavaScript Python Java Go >}}
{{% codetab %}}
```csharp
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Register actor runtime with DI
services.AddActors(options =>
{
// Register actor types and configure actor settings
options.Actors.RegisterActor<MyActor>();
// Configure default settings
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
options.DrainOngoingCallTimeout = TimeSpan.FromSeconds(60);
options.DrainRebalancedActors = true;
options.RemindersStoragePartitions = 7;
options.ReentrancyConfig = new() { Enabled = false };
// Add a configuration for a specific actor type.
// This actor type must have a matching value in the base level 'entities' field. If it does not, the configuration will be ignored.
// If there is a matching entity, the values here will be used to overwrite any values specified in the root configuration.
// In this example, `ReentrantActor` has reentrancy enabled; however, 'MyActor' will not have reentrancy enabled.
options.Actors.RegisterActor<ReentrantActor>(typeOptions: new()
{
ReentrancyConfig = new()
{
Enabled = true,
}
});
});
// Register additional services for use with actors
services.AddSingleton<BankService>();
}
```
[See the .NET SDK documentation on registring actors]({{< ref "dotnet-actors-usage.md#registring-actors" >}}).
{{% /codetab %}}
{{% codetab %}}
<!--javascript-->
```js
import { CommunicationProtocolEnum, DaprClient, DaprServer } from "@dapr/dapr";
// Configure the actor runtime with the DaprClientOptions.
const clientOptions = {
actor: {
actorIdleTimeout: "1h",
actorScanInterval: "30s",
drainOngoingCallTimeout: "1m",
drainRebalancedActors: true,
reentrancy: {
enabled: true,
maxStackDepth: 32,
},
remindersStoragePartitions: 0,
},
};
// Use the options when creating DaprServer and DaprClient.
// Note, DaprServer creates a DaprClient internally, which needs to be configured with clientOptions.
const server = new DaprServer(serverHost, serverPort, daprHost, daprPort, clientOptions);
const client = new DaprClient(daprHost, daprPort, CommunicationProtocolEnum.HTTP, clientOptions);
```
[See the documentation on writing actors with the JavaScript SDK]({{< ref "js-actors.md#registering-actors" >}}).
{{% /codetab %}}
{{% codetab %}}
<!--python-->
```python
from datetime import timedelta
from dapr.actor.runtime.config import ActorRuntimeConfig, ActorReentrancyConfig
ActorRuntime.set_actor_config(
ActorRuntimeConfig(
actor_idle_timeout=timedelta(hours=1),
actor_scan_interval=timedelta(seconds=30),
drain_ongoing_call_timeout=timedelta(minutes=1),
drain_rebalanced_actors=True,
reentrancy=ActorReentrancyConfig(enabled=False),
remindersStoragePartitions=7
)
)
```
[See the documentation on running actors with the Python SDK]({{< ref "python-actor.md" >}})
{{% /codetab %}}
{{% codetab %}}
<!--java-->
```java
// import io.dapr.actors.runtime.ActorRuntime;
// import java.time.Duration;
ActorRuntime.getInstance().getConfig().setActorIdleTimeout(Duration.ofMinutes(60));
ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(30));
ActorRuntime.getInstance().getConfig().setDrainOngoingCallTimeout(Duration.ofSeconds(60));
ActorRuntime.getInstance().getConfig().setDrainBalancedActors(true);
ActorRuntime.getInstance().getConfig().setActorReentrancyConfig(false, null);
ActorRuntime.getInstance().getConfig().setRemindersStoragePartitions(7);
```
[See the documentation on writing actors with the Java SDK]({{< ref "java.md#actors" >}}).
{{% /codetab %}}
{{% codetab %}}
<!--go-->
```go
const (
defaultActorType = "basicType"
reentrantActorType = "reentrantType"
)
type daprConfig struct {
Entities []string `json:"entities,omitempty"`
ActorIdleTimeout string `json:"actorIdleTimeout,omitempty"`
ActorScanInterval string `json:"actorScanInterval,omitempty"`
DrainOngoingCallTimeout string `json:"drainOngoingCallTimeout,omitempty"`
DrainRebalancedActors bool `json:"drainRebalancedActors,omitempty"`
Reentrancy config.ReentrancyConfig `json:"reentrancy,omitempty"`
EntitiesConfig []config.EntityConfig `json:"entitiesConfig,omitempty"`
}
var daprConfigResponse = daprConfig{
Entities: []string{defaultActorType, reentrantActorType},
ActorIdleTimeout: actorIdleTimeout,
ActorScanInterval: actorScanInterval,
DrainOngoingCallTimeout: drainOngoingCallTimeout,
DrainRebalancedActors: drainRebalancedActors,
Reentrancy: config.ReentrancyConfig{Enabled: false},
EntitiesConfig: []config.EntityConfig{
{
// Add a configuration for a specific actor type.
// This actor type must have a matching value in the base level 'entities' field. If it does not, the configuration will be ignored.
// If there is a matching entity, the values here will be used to overwrite any values specified in the root configuration.
// In this example, `reentrantActorType` has reentrancy enabled; however, 'defaultActorType' will not have reentrancy enabled.
Entities: []string{reentrantActorType},
Reentrancy: config.ReentrancyConfig{
Enabled: true,
MaxStackDepth: &maxStackDepth,
},
},
},
}
func configHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(daprConfigResponse)
}
```
[See an example for using actors with the Go SDK](https://github.com/dapr/go-sdk/tree/main/examples/actor).
{{% /codetab %}}
{{< /tabs >}}
## Next steps
{{< button text="Enable actor reminder partitioning >>" page="howto-actors-partitioning.md" >}}
## Related links
- Refer to the [Dapr SDK documentation and examples]({{< ref "developing-applications/sdks/#sdk-languages" >}}).
- [Actors API reference]({{< ref actors_api.md >}})
- [Actors overview]({{< ref actors-overview.md >}})

View File

@ -8,8 +8,6 @@ aliases:
- "/developing-applications/building-blocks/actors/actors-background"
---
## Actor timers and reminders
Actors can schedule periodic work on themselves by registering either timers or reminders.
The functionality of timers and reminders is very similar. The main difference is that Dapr actor runtime is not retaining any information about timers after deactivation, while persisting the information about reminders using Dapr actor state provider.
@ -47,7 +45,7 @@ The actor runtime validates correctness of the scheduling configuration and retu
When you specify both the number of repetitions in `period` as well as `ttl`, the timer/reminder will be stopped when either condition is met.
### Actor timers
## Actor timers
You can register a callback on actor to be executed based on a timer.
@ -63,7 +61,7 @@ You can create a timer for an actor by calling the HTTP/gRPC request to Dapr as
POST/PUT http://localhost:3500/v1.0/actors/<actorType>/<actorId>/timers/<name>
```
**Examples**
### Examples
The timer parameters are specified in the request body.
@ -107,7 +105,7 @@ DELETE http://localhost:3500/v1.0/actors/<actorType>/<actorId>/timers/<name>
Refer [api spec]({{< ref "actors_api.md#invoke-timer" >}}) for more details.
### Actor reminders
## Actor reminders
Reminders are a mechanism to trigger *persistent* callbacks on an actor at specified times. Their functionality is similar to timers. But unlike timers, reminders are triggered under all circumstances until the actor explicitly unregisters them or the actor is explicitly deleted or the number in invocations is exhausted. Specifically, reminders are triggered across actor deactivations and failovers because the Dapr actor runtime persists the information about the actors' reminders using Dapr actor state provider.
@ -119,7 +117,7 @@ POST/PUT http://localhost:3500/v1.0/actors/<actorType>/<actorId>/reminders/<name
The request structure for reminders is identical to those of actors. Please refer to the [actor timers examples]({{< ref "#actor-timers" >}}).
#### Retrieve actor reminder
### Retrieve actor reminder
You can retrieve the actor reminder by calling
@ -127,7 +125,7 @@ You can retrieve the actor reminder by calling
GET http://localhost:3500/v1.0/actors/<actorType>/<actorId>/reminders/<name>
```
#### Remove the actor reminder
### Remove the actor reminder
You can remove the actor reminder by calling
@ -139,22 +137,20 @@ Refer [api spec]({{< ref "actors_api.md#invoke-reminder" >}}) for more details.
## Error handling
When an actor's method completes successfully, the runtime will contineu to invoke the method at the specified timer or reminder schedule. However, if the method throws an exception, the runtime catches it and logs the error message, without retrying.
todo: where is logged?
When an actor's method completes successfully, the runtime will contineu to invoke the method at the specified timer or reminder schedule. However, if the method throws an exception, the runtime catches it and logs the error message in the Dapr sidecar logs, without retrying.
To allow actors to recover from failures and retry after a crash or restart, you can persist an actor's state by configuring a state store, like Redis or Azure Cosmos DB.
todo: how is the actor state updated? or is it not?
todo: does the timer get removed if not configured by a state store? example of configuring?
If an invocation of the method fails, the timer is not removed. Timers are only removed when:
- The sidecar crashes
- The executions run out
- You delete it explicitly
## Next steps
{{< button text="Use virtual actors >>" page="howto-actors.md" >}}
{{< button text="Configure actor runtime behavior >>" page="actors-runtime-config.md" >}}
## Related links
- [Actors API reference]({{< ref actors_api.md >}})
- [Actors overview]({{< ref actors-overview.md >}})
- Actors using the:
- [.NET SDK]({{< ref dotnet-actors.md >}})
- [Python SDK]({{< ref python-actor.md >}})
- [Java SDK]({{< ref js-actors.md >}})
- [Actors overview]({{< ref actors-overview.md >}})

View File

@ -0,0 +1,196 @@
---
type: docs
title: "How to: Enable partitioning of actor reminders"
linkTitle: "How to: Partition reminders"
weight: 50
description: "Enable actor reminders partitioning for your application"
aliases:
- "/developing-applications/building-blocks/actors/actors-background"
---
[Actor reminders]({{< ref "howto-actors-partitioning.md#actor-reminders" >}}) are persisted and continue to be triggered after sidecar restarts. Applications with multiple reminders registered can experience the following issues:
- Low throughput on reminders registration and de-registration
- Limited number of reminders registered based on the single record size limit on the state store
To sidestep these issues, applications can enable partitioning of actor reminders while data is distributed in multiple keys in the state store.
1. A metadata record in `actors\|\|<actor type>\|\|metadata` is used to store the persisted configuration for a given actor type.
1. Multiple records store subsets of the reminders for the same actor type.
| Key | Value |
| ----------- | ----------- |
| `actors\|\|<actor type>\|\|metadata` | `{ "id": <actor metadata identifier>, "actorRemindersMetadata": { "partitionCount": <number of partitions for reminders> } }` |
| `actors\|\|<actor type>\|\|<actor metadata identifier>\|\|reminders\|\|1` | `[ <reminder 1-1>, <reminder 1-2>, ... , <reminder 1-n> ]` |
| `actors\|\|<actor type>\|\|<actor metadata identifier>\|\|reminders\|\|2` | `[ <reminder 1-1>, <reminder 1-2>, ... , <reminder 1-m> ]` |
If you need to change the number of partitions, Dapr's sidecar will automatically redistribute the reminders' set.
## Configure the actor runtime to partition actor reminders
Similar to other actor configuration elements, the actor runtime provides the appropriate configuration to partition actor reminders via the actor's endpoint for `GET /dapr/config`. Select your preferred language for an actor runtime configuration example.
{{< tabs ".NET" JavaScript Python Java Go >}}
{{% codetab %}}
<!--dotnet-->
```csharp
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Register actor runtime with DI
services.AddActors(options =>
{
// Register actor types and configure actor settings
options.Actors.RegisterActor<MyActor>();
// Configure default settings
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
options.RemindersStoragePartitions = 7;
});
// Register additional services for use with actors
services.AddSingleton<BankService>();
}
```
[See the .NET SDK documentation on registring actors]({{< ref "dotnet-actors-usage.md#registring-actors" >}}).
{{% /codetab %}}
{{% codetab %}}
<!--javascript-->
```js
import { CommunicationProtocolEnum, DaprClient, DaprServer } from "@dapr/dapr";
// Configure the actor runtime with the DaprClientOptions.
const clientOptions = {
actor: {
remindersStoragePartitions: 0,
},
};
const actor = builder.build(new ActorId("my-actor"));
// Register a reminder, it has a default callback: `receiveReminder`
await actor.registerActorReminder(
"reminder-id", // Unique name of the reminder.
Temporal.Duration.from({ seconds: 2 }), // DueTime
Temporal.Duration.from({ seconds: 1 }), // Period
Temporal.Duration.from({ seconds: 1 }), // TTL
100, // State to be sent to reminder callback.
);
// Delete the reminder
await actor.unregisterActorReminder("reminder-id");
```
[See the documentation on writing actors with the JavaScript SDK]({{< ref "js-actors.md#registering-actors" >}}).
{{% /codetab %}}
{{% codetab %}}
<!--python-->
```python
from datetime import timedelta
ActorRuntime.set_actor_config(
ActorRuntimeConfig(
actor_idle_timeout=timedelta(hours=1),
actor_scan_interval=timedelta(seconds=30),
remindersStoragePartitions=7
)
)
```
[See the documentation on running actors with the Python SDK]({{< ref "python-actor.md" >}})
{{% /codetab %}}
{{% codetab %}}
<!--java-->
```java
// import io.dapr.actors.runtime.ActorRuntime;
// import java.time.Duration;
ActorRuntime.getInstance().getConfig().setActorIdleTimeout(Duration.ofMinutes(60));
ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(30));
ActorRuntime.getInstance().getConfig().setRemindersStoragePartitions(7);
```
[See the documentation on writing actors with the Java SDK]({{< ref "java.md#actors" >}}).
{{% /codetab %}}
{{% codetab %}}
<!--go-->
```go
type daprConfig struct {
Entities []string `json:"entities,omitempty"`
ActorIdleTimeout string `json:"actorIdleTimeout,omitempty"`
ActorScanInterval string `json:"actorScanInterval,omitempty"`
DrainOngoingCallTimeout string `json:"drainOngoingCallTimeout,omitempty"`
DrainRebalancedActors bool `json:"drainRebalancedActors,omitempty"`
RemindersStoragePartitions int `json:"remindersStoragePartitions,omitempty"`
}
var daprConfigResponse = daprConfig{
[]string{defaultActorType},
actorIdleTimeout,
actorScanInterval,
drainOngoingCallTimeout,
drainRebalancedActors,
7,
}
func configHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(daprConfigResponse)
}
```
[See an example for using actors with the Go SDK](https://github.com/dapr/go-sdk/tree/main/examples/actor).
{{% /codetab %}}
{{< /tabs >}}
The following is an example of a valid configuration for reminder partitioning:
```json
{
"entities": [ "MyActorType", "AnotherActorType" ],
"remindersStoragePartitions": 7
}
```
## Handle configuration changes
To configure actor reminders partitioning, Dapr persists the actor type metadata in the actor's state store. This allows the configuration changes to be applied globally, not just in a single sidecar instance.
In addition, **you can only increase the number of partitions**, not decrease. This allows Dapr to automatically redistribute the data on a rolling restart, where one or more partition configurations might be active.
## Demo
Watch [this video for a demo of actor reminder partitioning](https://youtu.be/ZwFOEUYe1WA?t=1493):
<div class="embed-responsive embed-responsive-16by9">
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/ZwFOEUYe1WA?start=1495" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## Next steps
{{< button text="Interact with virtual actors >>" page="howto-actors.md" >}}
## Related links
- [Actors API reference]({{< ref actors_api.md >}})
- [Actors overview]({{< ref actors-overview.md >}})

View File

@ -1,12 +1,14 @@
---
type: docs
title: "How-to: Use virtual actors in Dapr"
linkTitle: "How-To: Virtual actors"
weight: 40
description: Learn more about the actor pattern
title: "How-to: Interact with virtual actors using scripting"
linkTitle: "How-To: Interact with virtual actors"
weight: 60
description: Invoke the actor method for state management
---
## Actor method invocation
Learn how to use virtual actors by calling HTTP/gRPC endpoints.
## Invoke the actor method
You can interact with Dapr to invoke the actor method by calling HTTP/gRPC endpoint.
@ -14,299 +16,28 @@ You can interact with Dapr to invoke the actor method by calling HTTP/gRPC endpo
POST/GET/PUT/DELETE http://localhost:3500/v1.0/actors/<actorType>/<actorId>/method/<method>
```
You can provide any data for the actor method in the request body and the response for the request is in response body which is data from actor method call.
Provide data for the actor method in the request body. The response for the request, which is data from actor method call, is in the response body.
Refer [api spec]({{< ref "actors_api.md#invoke-actor-method" >}}) for more details.
Refer [to the Actors API spec]({{< ref "actors_api.md#invoke-actor-method" >}}) for more details.
Alternatively, you can use the Dapr SDK in [.NET]({{< ref "dotnet-actors" >}}), [Java]({{< ref "java#actors" >}}), or [Python]({{< ref "python-actor" >}}).
{{% alert title="Note" color="primary" %}}
Alternatively, you can use [Dapr SDKs to use actors]({{< ref "developing-applications/sdks/#sdk-languages" >}}).
{{% /alert %}}
## Actor state management
## Save state with actors
Actors can save state reliably using state management capability.
You can interact with Dapr through HTTP/gRPC endpoints for state management.
You can interact with Dapr via HTTP/gRPC endpoints to save state reliably using the Dapr actor state mangement capabaility.
To use actors, your state store must support multi-item transactions. This means your state store [component](https://github.com/dapr/components-contrib/tree/master/state) must implement the [TransactionalStore](https://github.com/dapr/components-contrib/blob/master/state/transactional_store.go) interface. The list of components that support transactions/actors can be found here: [supported state stores]({{< ref supported-state-stores.md >}}). Only a single state store component can be used as the statestore for all actors.
To use actors, your state store must support multi-item transactions. This means your [state store component](https://github.com/dapr/components-contrib/tree/master/state) must implement the [`TransactionalStore`](https://github.com/dapr/components-contrib/blob/master/state/transactional_store.go) interface.
## Actor timers and reminders
[See the list of components that support transactions/actors]({{< ref supported-state-stores.md >}}). Only a single state store component can be used as the state store for all actors.
Actors can schedule periodic work on themselves by registering either timers or reminders. Set timers or reminders for your actors using the [Actors Timers and Reminders]({{< ref actors-timers-reminders.md >}}) guide.
## Next steps
## Actor runtime configuration
{{< button text="Actor reentrancy >>" page="actor-reentrancy.md" >}}
You can configure the Dapr actor runtime configuration to modify the default runtime behavior.
## Related links
### Configuration parameters
- `entities` - The actor types supported by this host.
- `actorIdleTimeout` - The timeout before deactivating an idle actor. Checks for timeouts occur every `actorScanInterval` interval. **Default: 60 minutes**
- `actorScanInterval` - The duration which specifies how often to scan for actors to deactivate idle actors. Actors that have been idle longer than actor_idle_timeout will be deactivated. **Default: 30 seconds**
- `drainOngoingCallTimeout` - The duration when in the process of draining rebalanced actors. This specifies the timeout for the current active actor method to finish. If there is no current actor method call, this is ignored. **Default: 60 seconds**
- `drainRebalancedActors` - If true, Dapr will wait for `drainOngoingCallTimeout` duration to allow a current actor call to complete before trying to deactivate an actor. **Default: true**
- `reentrancy` (ActorReentrancyConfig) - Configure the reentrancy behavior for an actor. If not provided, reentrancy is disabled. **Default: disabled**
**Default: false**
- `remindersStoragePartitions` - Configure the number of partitions for actor's reminders. If not provided, all reminders are saved as a single record in actor's state store. **Default: 0**
- `entitiesConfig` - Configure each actor type individually with an array of configurations. Any entity specified in the individual entity configurations must also be specified in the top level `entities` field. **Default: None**
{{< tabs Java Dotnet Python Go >}}
{{% codetab %}}
```java
// import io.dapr.actors.runtime.ActorRuntime;
// import java.time.Duration;
ActorRuntime.getInstance().getConfig().setActorIdleTimeout(Duration.ofMinutes(60));
ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(30));
ActorRuntime.getInstance().getConfig().setDrainOngoingCallTimeout(Duration.ofSeconds(60));
ActorRuntime.getInstance().getConfig().setDrainBalancedActors(true);
ActorRuntime.getInstance().getConfig().setActorReentrancyConfig(false, null);
ActorRuntime.getInstance().getConfig().setRemindersStoragePartitions(7);
```
See [this example](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/actors/DemoActorService.java)
{{% /codetab %}}
{{% codetab %}}
```csharp
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Register actor runtime with DI
services.AddActors(options =>
{
// Register actor types and configure actor settings
options.Actors.RegisterActor<MyActor>();
// Configure default settings
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
options.DrainOngoingCallTimeout = TimeSpan.FromSeconds(60);
options.DrainRebalancedActors = true;
options.RemindersStoragePartitions = 7;
options.ReentrancyConfig = new() { Enabled = false };
// Add a configuration for a specific actor type.
// This actor type must have a matching value in the base level 'entities' field. If it does not, the configuration will be ignored.
// If there is a matching entity, the values here will be used to overwrite any values specified in the root configuration.
// In this example, `ReentrantActor` has reentrancy enabled; however, 'MyActor' will not have reentrancy enabled.
options.Actors.RegisterActor<ReentrantActor>(typeOptions: new()
{
ReentrancyConfig = new()
{
Enabled = true,
}
});
});
// Register additional services for use with actors
services.AddSingleton<BankService>();
}
```
See the .NET SDK [documentation](https://github.com/dapr/dotnet-sdk/blob/master/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-usage.md#registering-actors).
{{% /codetab %}}
{{% codetab %}}
```python
from datetime import timedelta
from dapr.actor.runtime.config import ActorRuntimeConfig, ActorReentrancyConfig
ActorRuntime.set_actor_config(
ActorRuntimeConfig(
actor_idle_timeout=timedelta(hours=1),
actor_scan_interval=timedelta(seconds=30),
drain_ongoing_call_timeout=timedelta(minutes=1),
drain_rebalanced_actors=True,
reentrancy=ActorReentrancyConfig(enabled=False),
remindersStoragePartitions=7
)
)
```
{{% /codetab %}}
{{% codetab %}}
```go
const (
defaultActorType = "basicType"
reentrantActorType = "reentrantType"
)
type daprConfig struct {
Entities []string `json:"entities,omitempty"`
ActorIdleTimeout string `json:"actorIdleTimeout,omitempty"`
ActorScanInterval string `json:"actorScanInterval,omitempty"`
DrainOngoingCallTimeout string `json:"drainOngoingCallTimeout,omitempty"`
DrainRebalancedActors bool `json:"drainRebalancedActors,omitempty"`
Reentrancy config.ReentrancyConfig `json:"reentrancy,omitempty"`
EntitiesConfig []config.EntityConfig `json:"entitiesConfig,omitempty"`
}
var daprConfigResponse = daprConfig{
Entities: []string{defaultActorType, reentrantActorType},
ActorIdleTimeout: actorIdleTimeout,
ActorScanInterval: actorScanInterval,
DrainOngoingCallTimeout: drainOngoingCallTimeout,
DrainRebalancedActors: drainRebalancedActors,
Reentrancy: config.ReentrancyConfig{Enabled: false},
EntitiesConfig: []config.EntityConfig{
{
// Add a configuration for a specific actor type.
// This actor type must have a matching value in the base level 'entities' field. If it does not, the configuration will be ignored.
// If there is a matching entity, the values here will be used to overwrite any values specified in the root configuration.
// In this example, `reentrantActorType` has reentrancy enabled; however, 'defaultActorType' will not have reentrancy enabled.
Entities: []string{reentrantActorType},
Reentrancy: config.ReentrancyConfig{
Enabled: true,
MaxStackDepth: &maxStackDepth,
},
},
},
}
func configHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(daprConfigResponse)
}
```
{{% /codetab %}}
{{< /tabs >}}
Refer to the documentation and examples of the [Dapr SDKs]({{< ref "developing-applications/sdks/#sdk-languages" >}}) for more details.
## Partitioning reminders
Actor reminders are persisted and continue to be triggered after sidecar restarts. Applications with multiple reminders registered can experience the following issues:
- Low throughput on reminders registration and de-registration
- Limit on the total number of reminders registered based on the single record size limit on the state store
Applications can enable partitioning of actor reminders while data is distributed in multiple keys in the state store.
1. A metadata record in `actors\|\|<actor type>\|\|metadata` is used to store persisted configuration for a given actor type.
1. Multiple records store subsets of the reminders for the same actor type.
| Key | Value |
| ----------- | ----------- |
| `actors\|\|<actor type>\|\|metadata` | `{ "id": <actor metadata identifier>, "actorRemindersMetadata": { "partitionCount": <number of partitions for reminders> } }` |
| `actors\|\|<actor type>\|\|<actor metadata identifier>\|\|reminders\|\|1` | `[ <reminder 1-1>, <reminder 1-2>, ... , <reminder 1-n> ]` |
| `actors\|\|<actor type>\|\|<actor metadata identifier>\|\|reminders\|\|2` | `[ <reminder 1-1>, <reminder 1-2>, ... , <reminder 1-m> ]` |
| ... | ... |
If you need to change the number of partitions, Dapr's sidecar will automatically redistribute the reminders's set.
### Enabling actor reminders partitioning
#### Actor runtime configuration for actor reminders partitioning
Similar to other actor configuration elements, the actor runtime provides the appropriate configuration to partition actor reminders via the actor's endpoint for `GET /dapr/config`.
{{< tabs Java Dotnet Python Go >}}
{{% codetab %}}
```java
// import io.dapr.actors.runtime.ActorRuntime;
// import java.time.Duration;
ActorRuntime.getInstance().getConfig().setActorIdleTimeout(Duration.ofMinutes(60));
ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(30));
ActorRuntime.getInstance().getConfig().setRemindersStoragePartitions(7);
```
For more information, see [the Java actors example](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/actors/DemoActorService.java)
{{% /codetab %}}
{{% codetab %}}
```csharp
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Register actor runtime with DI
services.AddActors(options =>
{
// Register actor types and configure actor settings
options.Actors.RegisterActor<MyActor>();
// Configure default settings
options.ActorIdleTimeout = TimeSpan.FromMinutes(60);
options.ActorScanInterval = TimeSpan.FromSeconds(30);
options.RemindersStoragePartitions = 7;
});
// Register additional services for use with actors
services.AddSingleton<BankService>();
}
```
See the .NET SDK [documentation for registering actors](https://github.com/dapr/dotnet-sdk/blob/master/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-usage.md#registering-actors).
{{% /codetab %}}
{{% codetab %}}
```python
from datetime import timedelta
ActorRuntime.set_actor_config(
ActorRuntimeConfig(
actor_idle_timeout=timedelta(hours=1),
actor_scan_interval=timedelta(seconds=30),
remindersStoragePartitions=7
)
)
```
{{% /codetab %}}
{{% codetab %}}
```go
type daprConfig struct {
Entities []string `json:"entities,omitempty"`
ActorIdleTimeout string `json:"actorIdleTimeout,omitempty"`
ActorScanInterval string `json:"actorScanInterval,omitempty"`
DrainOngoingCallTimeout string `json:"drainOngoingCallTimeout,omitempty"`
DrainRebalancedActors bool `json:"drainRebalancedActors,omitempty"`
RemindersStoragePartitions int `json:"remindersStoragePartitions,omitempty"`
}
var daprConfigResponse = daprConfig{
[]string{defaultActorType},
actorIdleTimeout,
actorScanInterval,
drainOngoingCallTimeout,
drainRebalancedActors,
7,
}
func configHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(daprConfigResponse)
}
```
{{% /codetab %}}
{{< /tabs >}}
The following is an example of a valid configuration for reminder partitioning:
```json
{
"entities": [ "MyActorType", "AnotherActorType" ],
"remindersStoragePartitions": 7
}
```
#### Handling configuration changes
To configure actor reminders partitioning, Dapr persists the actor type metadata in the actor's state store. This allows the configuration changes to be applied globally, not just in a single sidecar instance.
Also, **you can only increase the number of partitions**, not decrease. This allows Dapr to automatically redistribute the data on a rolling restart where one or more partition configurations might be active.
#### Demo
Watch [this video for a demo of actor reminder partitioning](https://youtu.be/ZwFOEUYe1WA?t=1493):
<div class="embed-responsive embed-responsive-16by9">
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/ZwFOEUYe1WA?start=1495" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
- Refer to the [Dapr SDK documentation and examples]({{< ref "developing-applications/sdks/#sdk-languages" >}}).
- [Actors API reference]({{< ref actors_api.md >}})
- [Actors overview]({{< ref actors-overview.md >}})