integração Orleans e .NET Aspire

.NET Aspire fornece uma abordagem simplificada para a criação de aplicativos nativos de nuvem com suporte interno para Orleans. Começando com Orleans 8.0, você pode usar Aspire para orquestrar seu cluster Orleans, gerenciar recursos de backup (como Redis ou Armazenamento do Azure) e configurar automaticamente a descoberta de serviços, a observabilidade e as verificações de integridade.

Visão geral

Orleans integração com .NET Aspire usa o pacote Aspire.Hosting.Orleans em seu projeto AppHost. Este pacote fornece métodos de extensão para:

  • Definir Orleans como um recurso distribuído
  • Configurar provedores de clustering (Redis, Armazenamento do Azure, ADO.NET)
  • Configurar provedores de armazenamento de grãos
  • Configurar provedores de lembrete
  • Configurar provedores de diretório de grains
  • Modelar relacionamentos entre silo e cliente

Pré-requisitos

Antes de usar Orleans com Aspire, verifique se você tem:

Pacotes necessários

Sua solução precisa das seguintes referências de pacote:

Projeto AppHost

<ItemGroup>
  <PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.3" />
  <PackageReference Include="Aspire.Hosting.Orleans" Version="13.1.3" />
  <PackageReference Include="Aspire.Hosting.Redis" Version="13.1.3" />
</ItemGroup>

Orleans projeto de silo

<ItemGroup>
  <PackageReference Include="Microsoft.Orleans.Server" Version="10.1.0" />
  <PackageReference Include="Microsoft.Orleans.Clustering.Redis" Version="10.1.0" />
  <PackageReference Include="Aspire.StackExchange.Redis" Version="13.2.4" />
</ItemGroup>

Projeto clienteOrleans (se separado do silo)

<ItemGroup>
  <PackageReference Include="Microsoft.Orleans.Client" Version="10.1.0" />
  <PackageReference Include="Microsoft.Orleans.Clustering.Redis" Version="10.1.0" />
  <PackageReference Include="Aspire.StackExchange.Redis" Version="13.2.4" />
</ItemGroup>

Configurar o AppHost

O projeto AppHost orquestra seu Orleans cluster e suas dependências.

Cluster Orleans básico com cluster Redis

public static void BasicOrleansCluster(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    // Add Redis for Orleans clustering
    var redis = builder.AddRedis("orleans-redis");

    // Define the Orleans resource with Redis clustering
    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis);

    // Add the Orleans silo project
    builder.AddProject<Projects.Silo>("silo")
        .WithReference(orleans)
        .WaitFor(redis)
        .WithReplicas(3);

    builder.Build().Run();
}

Orleans com armazenamento de grãos e notificações

public static void OrleansWithStorageAndReminders(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    var redis = builder.AddRedis("orleans-redis");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis)
        .WithGrainStorage("Default", redis)
        .WithGrainStorage("PubSubStore", redis)
        .WithReminders(redis);

    builder.AddProject<Projects.Silo>("silo")
        .WithReference(orleans)
        .WaitFor(redis)
        .WithReplicas(3);

    builder.Build().Run();
}

Projetos de silo e cliente separados

Quando seu cliente Orleans é executado em um processo separado (como um frontend web), use o método .AsClient():

public static void SeparateSiloAndClient(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    var redis = builder.AddRedis("orleans-redis");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis)
        .WithGrainStorage("Default", redis);

    // Backend Orleans silo cluster
    var silo = builder.AddProject<Projects.Silo>("backend")
        .WithReference(orleans)
        .WaitFor(redis)
        .WithReplicas(5);

    // Frontend web project as Orleans client
    builder.AddProject<Projects.Client>("frontend")
        .WithReference(orleans.AsClient())  // Client-only reference
        .WaitFor(silo);

    builder.Build().Run();
}

Configurar o projeto de silo Orleans

Em seu projeto de silo Orleans, configure Orleans para usar os Aspirerecursos fornecidos por:

public static void BasicSiloConfiguration(string[] args)
{
    var builder = Host.CreateApplicationBuilder(args);

    // Add Aspire service defaults (OpenTelemetry, health checks, etc.)
    builder.AddServiceDefaults();

    // Add the Aspire Redis client for Orleans
    builder.AddKeyedRedisClient("orleans-redis");

    // Configure Orleans - Aspire injects all configuration automatically
    builder.UseOrleans();

    builder.Build().Run();
}

Dica

Ao usar .NET Aspire, o UseOrleans sem parâmetros normalmente é tudo o que você precisa. Aspire injeta a configuração de Orleans (ID do cluster, ID de serviço, pontos de extremidade e configurações de provedor) por meio de variáveis de ambiente que são lidas automaticamente por Orleans. Você só precisa da sobrecarga de delegado UseOrleans(siloBuilder => {...}) quando precisar de configuração manual adicional além do que Aspire fornece.

Importante

Você deve chamar o método apropriado AddKeyed* (como AddKeyedRedisClient, AddKeyedAzureTableClientou AddKeyedAzureBlobClient) para registrar o recurso de backup no contêiner de injeção de dependência. Os provedores Orleans pesquisam recursos pelo nome do serviço com chave — se você ignorar esta etapa, Orleans não conseguirá resolver o recurso e lançará um erro de resolução de dependência em tempo de execução. Isso se aplica a todos os Aspirerecursos gerenciados usados com Orleans.

Configurar com cadeia de conexão explícita

Se você precisar de controle explícito sobre a cadeia de conexão, poderá lê-la na configuração:

public static void ExplicitConnectionConfiguration(string[] args)
{
    var builder = Host.CreateApplicationBuilder(args);

    builder.AddServiceDefaults();
    builder.AddKeyedRedisClient("orleans-redis");

    builder.UseOrleans(siloBuilder =>
    {
        var redisConnectionString = builder.Configuration.GetConnectionString("orleans-redis");

        siloBuilder.UseRedisClustering(options =>
        {
            options.ConfigurationOptions =
                ConfigurationOptions.Parse(redisConnectionString!);
        });

        siloBuilder.AddRedisGrainStorageAsDefault(options =>
        {
            options.ConfigurationOptions =
                ConfigurationOptions.Parse(redisConnectionString!);
        });
    });

    builder.Build().Run();
}

Configurar o projeto cliente Orleans

Para projetos de clientes separados, configure o cliente da Orleans mesma forma:

public static void BasicClientConfiguration(string[] args)
{
    var builder = Host.CreateApplicationBuilder(args);

    builder.AddServiceDefaults();
    builder.AddKeyedRedisClient("orleans-redis");

    // Configure Orleans client - Aspire injects clustering configuration automatically
    builder.UseOrleansClient();

    builder.Build().Run();
}

Referência de métodos de extensão AppHost

O Aspire.Hosting.Orleans pacote fornece estes métodos de extensão:

Métodos principais

Método Description
builder.AddOrleans(name) Adiciona um Orleans recurso ao aplicativo distribuído com o nome especificado.
.WithClusterId(id) Define o ClusterId Orleans. Aceita uma cadeia de caracteres ou ParameterResource. Se não for especificado, uma ID exclusiva será gerada automaticamente.
.WithServiceId(id) Define a Orleans ServiceId. Aceita uma cadeia de caracteres ou ParameterResource. Se não for especificado, uma ID exclusiva será gerada automaticamente.
.AsClient() Retorna uma referência exclusiva do cliente ao recurso Orleans (não inclui as capabilidades de silo).
project.WithReference(orleans) Adiciona a referência do recurso Orleans a um projeto, habilitando a injeção de configuração.

Observação

Quando você configura um recurso de suporte usando .WithClustering(resource), .WithGrainStorage(name, resource), ou métodos semelhantes, o recurso Orleans inclui automaticamente uma referência a esse recurso de apoio. Você não precisa chamar .WithReference() separadamente para cada recurso de backup, apenas .WithReference(orleans) é necessário. No entanto, você deve usar .WaitFor() no recurso de suporte para garantir que ele esteja pronto antes do início do silo.

Clustering

Método Description
.WithClustering(resource) Configura o clustering Orleans para usar o recurso especificado (Redis, Armazenamento do Azure, Cosmos DB, etc.).
.WithDevelopmentClustering() Configura o clustering de host único na memória somente para desenvolvimento local. Não adequado para produção.

Armazenamento de grãos

Método Description
.WithGrainStorage(name, resource) Configura um provedor de armazenamento de grãos nomeado usando o recurso especificado.
.WithMemoryGrainStorage(name) Configura o armazenamento de grains na memória para o nome especificado. Os dados são perdidos na reinicialização do silo.

Lembretes

Método Description
.WithReminders(resource) Configura o Orleans serviço de lembrete usando o recurso especificado.
.WithMemoryReminders() Configura lembretes na memória para desenvolvimento. Lembretes são perdidos na reinicialização do silo.

Transmissão ao vivo

Método Description
.WithStreaming(name, resource) Configura um provedor de fluxo nomeado usando o recurso especificado (por exemplo, Armazenamento de Filas do Azure).
.WithMemoryStreaming(name) Configura o streaming na memória para desenvolvimento.
.WithBroadcastChannel(name) Configura um provedor de canal de transmissão com o nome especificado.

Diretório de Grãos

Método Description
.WithGrainDirectory(name, resource) Configura um diretório de grãos nomeado usando o recurso especificado.

Padrão de padrões de serviço

Aspire usa um padrão de projeto ServiceDefaults para compartilhar a configuração comum em todos os projetos. Para Orleans, isso normalmente inclui:

Configuração do OpenTelemetry

public static IHostApplicationBuilder AddServiceDefaults(
    this IHostApplicationBuilder builder)
{
    builder.ConfigureOpenTelemetry();
    builder.AddDefaultHealthChecks();
    
    return builder;
}

public static IHostApplicationBuilder ConfigureOpenTelemetry(
    this IHostApplicationBuilder builder)
{
    builder.Logging.AddOpenTelemetry(logging =>
    {
        logging.IncludeFormattedMessage = true;
        logging.IncludeScopes = true;
    });

    builder.Services.AddOpenTelemetry()
        .WithMetrics(metrics =>
        {
            metrics.AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation()
                .AddRuntimeInstrumentation()
                .AddMeter("Microsoft.Orleans");  // Orleans metrics
        })
        .WithTracing(tracing =>
        {
            tracing.AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation()
                .AddSource("Microsoft.Orleans.Runtime")
                .AddSource("Microsoft.Orleans.Application");
        });

    return builder;
}

Armazenamento do Azure com Aspire

Você pode usar recursos do Armazenamento do Azure para Orleans clustering e persistência:

public static void AzureStorageWithAspire(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    // Add Azure Storage for Orleans
    var storage = builder.AddAzureStorage("orleans-storage")
        .RunAsEmulator();  // Use Azurite emulator for local development

    var tables = storage.AddTables("orleans-tables");
    var blobs = storage.AddBlobs("orleans-blobs");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(tables)
        .WithGrainStorage("Default", blobs)
        .WithReminders(tables);

    builder.AddProject<Projects.Silo>("silo")
        .WithReference(orleans)
        .WaitFor(storage)
        .WithReplicas(3);

    builder.Build().Run();
}

Configuração de desenvolvimento versus produção

Aspire facilita a alternância entre configurações de desenvolvimento e produção:

Desenvolvimento local (usando emuladores)

public static void LocalDevelopment(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    var redis = builder.AddRedis("orleans-redis");
    // Redis container runs automatically during development

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis);

    // ...
}

Produção (usando serviços gerenciados)

public static void ProductionConfig(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    // Use existing Azure Cache for Redis
    var redis = builder.AddConnectionString("orleans-redis");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis);

    // ...
}

Exames de saúde

Aspire configura automaticamente os pontos de extremidade de verificação de integridade. Você pode adicionar verificações de integridade Orleans específicas:

public static void ConfigureHealthChecks(IHostApplicationBuilder builder)
{
    builder.Services.AddHealthChecks()
        .AddCheck<GrainHealthCheck>("orleans-grains")
        .AddCheck<SiloHealthCheck>("orleans-silo");
}

Práticas recomendadas

  1. Use ServiceDefaults: compartilhar configuração comum (OpenTelemetry, verificações de integridade) em todos os projetos usando um projeto ServiceDefaults.

  2. Aguardar dependências: sempre use .WaitFor() para garantir que os recursos de suporte (Redis, bancos de dados) estejam prontos antes do início dos silos Orleans.

  3. Configurar réplicas: Utilize .WithReplicas() para rodar múltiplas instâncias de silo para tolerância a falhas e escalabilidade.

  4. Projetos cliente separados: Para interfaces da Web, use .AsClient() para configurar o modo apenas para cliente.

  5. Use emuladores para desenvolvimento: Aspire pode executar Redis, Armazenamento do Azure (Azurite) e outras dependências localmente usando contêineres.

  6. Habilitar rastreamento distribuído: configure o OpenTelemetry com nomes de origem Orleans para rastrear chamadas de grains em todo o cluster.

Consulte também

.NET Aspire integração foi introduzida no Orleans 8.0. Para Orleans 7.0, você ainda pode implantar em ambientes orquestrados por Aspire, mas o pacote dedicado Aspire.Hosting.Orleans e seus métodos de extensão não estão disponíveis.

Considere atualizar para Orleans 8.0 ou posterior para aproveitar os Aspire recursos de integração.

A integração do .NET Aspire está disponível no Orleans 8.0 e posteriores. Orleans 3.x não dá suporte a .NET Aspire.