No artigo anterior, discuti a configuração de um ator simples. Este artigo foca em Virtual Actor, um conceito que amplia o modelo tradicional de atores com gerenciamento automático de ciclo de vida e comunicação simplificada.
Virtual Actor (Grain)
O modelo de Virtual Actor (ou grain), popularizado pelo framework Orleans da Microsoft, abstrai o gerenciamento manual do ciclo de vida dos atores. Enquanto atores tradicionais exigem criação explícita e referência via PID, os atores virtuais são identificados por uma chave única. O framework os cria, ativa ou reativa automaticamente conforme necessário. Essa abstração simplifica a escalabilidade em sistemas distribuídos, dissociando a identidade do ator de sua localização física ou estado.
Diferenças-chave em relação aos atores clássicos:
- Gerenciamento de Ciclo de Vida: O framework (ex: Orleans ou Proto.Actor) cuida da ativação/desativação.
- Endereçamento: A comunicação usa identificadores lógicos, não PIDs.
- Persistência de Estado: Integra camadas de gerenciamento de estado para tolerância a falhas.
Requisitos
- .NET 6+
- Pacotes NuGet:
- Proto.Actor
- Proto.Remote
- Proto.Cluster - Enables distributed virtual actor clusters via gRPC.
- Proto.Cluster.CodeGen
- Proto.Cluster.TestProvider
- Grpc.Tools
- Microsoft.Extensions.Hosting
Definindo o Virtual Actor (Grain)
O Proto.Actor usa Protocol Buffers para definir interfaces de atores. Crie um arquivo Greeting.proto
:
syntax = "proto3"; option csharp_namespace = "VirtualActor"; import "google/protobuf/empty.proto"; message SayHelloRequest { string name = 1; } service GreetingGrain { rpc SayHello(SayHelloRequest) returns (google.protobuf.Empty); }
Isso gera:
- Classes de requisição/resposta (ex:
SayHelloRequest
). - Classe base (
GreetingGrainBase
) para a lógica do ator.
Atualize o .csproj
para habilitar a geração de código:
<ItemGroup> <Protobuf Include="Greeting.proto"> <GrcpServices>None</GrcpServices> </Protobuf> </ItemGroup> <ItemGroup> <ProtoGrain Include="Greeting.proto" /> </ItemGroup>
Implementando o Ator
Crie uma classe GreetingActor
herdando de GreetingGrainBase
:
public class GreetingActor( IContext context, ClusterIdentity clusterIdentity, ILogger<GreetingActor> logger ) : GreetingGrainBase(context) { private int _invocationCount = 0; public override Task SayHello(SayHelloRequest request) { logger.LogInformation( "Hello {Name} (Cluster ID: {ClusterId} | Invocation Count: {Count})", request.Name, clusterIdentity.Identity, _invocationCount++ ); return Task.CompletedTask; } }
Detalhes:
- Gerenciamento de Estado:
_invocationCount
rastreia chamadas (thread-safe graças ao modelo de atores). - Injeção de Dependências:
ILogger
é injetado viaActivatorUtilities
.
Configurando o Sistema de Atores
Configure o cluster com TestProvider
(para desenvolvimento) e PartitionIdentityLookup
:
var actorSystemConfig = Proto.ActorSystemConfig.Setup(); var remoteConfig = GrpcNetRemoteConfig.BindToLocalhost(); var clusterConfig = ClusterConfig .Setup( clusterName: "VirtualActor", clusterProvider: new TestProvider(new TestProviderOptions(), new InMemAgent()), identityLookup: new PartitionIdentityLookup() ) .WithClusterKind( kind: GreetingGrainActor.Kind, prop: Props.FromProducer(() => new GreetingGrainActor((context, clusterIdentity) => ActivatorUtilities.CreateInstance<GreetingActor>(provider, context, clusterIdentity))) ); return new ActorSystem(actorSystemConfig) .WithServiceProvider(provider) .WithRemote(remoteConfig) .WithCluster(clusterConfig);
Integrando ao .NET
Registre o serviço de cluster como um IHostedService
:
public class ActorSystemClusterHostedService(ActorSystem actorSystem) : IHostedService { public async Task StartAsync(CancellationToken cancellationToken) { await actorSystem.Cluster().StartMemberAsync(); } public async Task StopAsync(CancellationToken cancellationToken) { await actorSystem.Cluster().ShutdownAsync(); } }
Registre em Program.cs
:
services.AddHostedService<ActorSystemClusterHostedService>();
Interagindo com Atores Virtuais
Use GetGreetingGrain
para referenciar um ator por ID:
var actor = actorSystem.Cluster().GetGreetingGrain(fromName); await actor.SayHello(new SayHelloRequest { Name = toName }, CancellationToken.None);
Exemplo de fluxo:
while (true) { Console.Write("Seu nome (ou 'q' para sair): "); var fromName = Console.ReadLine(); if (fromName == "q") break; Console.Write("Nome do destinatário: "); var toName = Console.ReadLine(); if (toName == "q") break; await actor.SayHello(new SayHelloRequest { Name = toName }); }
Benefícios dos Atores Virtuais
- Concorrência Simplificada: Processamento sequencial de mensagens evita condições de corrida.
- Escalabilidade Elástica: Adicione/remova nós sem reconfigurar atores.
- Resiliência: Reativação automática garante comportamento "sempre ativo".
Conclusão
Atores Virtuais (ou Grains) revolucionam o desenvolvimento de sistemas distribuídos ao abstrair complexidade enquanto mantêm os benefícios do modelo de atores. Com o Proto.Actor, desenvolvedores .NET podem:
- Focar na Lógica de Negócio: O framework gerencia ativação, escalabilidade e recuperação.
- Construir Sistemas Resilientes: Reativação automática e persistência de estado garantem tolerância a falhas.
- Escalar sem Esforço: Transparência de localização e clustering elástico distribuem carga entre nós.
Para produção:
- Substitua
TestProvider
por provedores como Kubernetes ou Consul. - Adicione armazenamento persistente (ex: Redis, PostgreSQL).
- Implemente monitoramento e health checks.
Referência
- Repositório completo: (GitHub)
- Documentação do Proto.Actor: Guia de Introdução a Grains/Virtual Actors (.NET)
Top comments (0)