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: _invocationCountrastreia 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 TestProviderpor 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)