教程:Hello world

此概述嵌入在 Hello World 示例应用程序中。

Orleans 的主要概念涉及 silo、客户端和一个或多个 grain。 创建 Orleans 应用涉及配置 silo、配置客户端和编写 grain。

配置接收器

通过 ISiloBuilder 编程方式配置孤岛以及多个补充选项类。 可以在 选项类列表中找到所有选项的列表。

public static async Task SiloMain(string[] args)
{
    await Host.CreateDefaultBuilder(args)
        .UseOrleans(siloBuilder =>
        {
            siloBuilder.UseLocalhostClustering()
                .Configure<ClusterOptions>(options =>
                {
                    options.ClusterId = "dev";
                    options.ServiceId = "HelloWorldApp";
                })
                .Configure<EndpointOptions>(
                    options => options.AdvertisedIPAddress = IPAddress.Loopback)
                .ConfigureLogging(logging => logging.AddConsole());
        })
        .RunConsoleAsync();
}

前面的代码:

  • 创建默认主机生成器。
  • 调用 UseOrleans 配置孤立服务器。
  • 使用 localhost 群集进行本地开发。
  • 配置群集和服务 ID。
  • 配置终结点以侦听环回。
  • 添加控制台日志记录。

通过 ISiloHostBuilder 编程方式配置孤岛以及多个补充选项类。 可以在 选项类列表中找到所有选项的列表。

static async Task<ISiloHost> StartSilo(string[] args)
{
    var siloHostBuilder = new SiloHostBuilder()
        .UseLocalhostClustering()
        .Configure<ClusterOptions>(options =>
        {
            options.ClusterId = "dev";
            options.ServiceId = "HelloWorldApp";
        })
        .Configure<EndpointOptions>(
            options => options.AdvertisedIPAddress = IPAddress.Loopback)
        .ConfigureApplicationParts(
            parts => parts.AddApplicationPart(typeof(HelloGrain).Assembly).WithReferences())
        .ConfigureLogging(logging => logging.AddConsole());

    var host = siloHostBuilder.Build();
    await host.StartAsync();

    return host;
}
选项 用途
.UseLocalhostClustering() 将客户端配置为连接到本地主机上的接收器。
ClusterOptions ClusterId 是 Orleans 群集的名称;对于孤岛和客户端,它必须相同,以便它们能够通信。 ServiceId 是用于应用程序的 ID,不能在部署之间更改。
EndpointOptions 告诉孤岛在哪里倾听。 对于此示例,请使用 loopback
选项 用途
ConfigureApplicationParts 将 grain 类和接口程序集作为应用程序部件添加到 Orleans 应用程序。 这在 7.0+ 中 Orleans 不需要,因为源生成器会自动处理此情况。

加载配置后,生成主机,然后异步启动它。

配置客户端

与孤岛类似,通过 IClientBuilder 和类似的选项类集合配置客户端。

public static async Task ClientMain(string[] args)
{
    using IHost host = Host.CreateDefaultBuilder(args)
        .UseOrleansClient(clientBuilder =>
        {
            clientBuilder.UseLocalhostClustering()
                .Configure<ClusterOptions>(options =>
                {
                    options.ClusterId = "dev";
                    options.ServiceId = "HelloWorldApp";
                });
        })
        .ConfigureLogging(logging => logging.AddConsole())
        .Build();

    await host.StartAsync();

    var client = host.Services.GetRequiredService<IClusterClient>();
    Console.WriteLine("Client successfully connected to silo host");

    await DoClientWork(client);

    await host.StopAsync();
}

前面的代码:

  • 创建默认主机生成器。
  • 调用 UseOrleansClient 以配置客户端。
  • 使用本地主机群集连接到本地存储体。
  • 配置群集和服务 ID 以匹配数据孤岛。
  • 启动主机并从服务提供商检索 IClusterClient

与孤岛类似,通过 IClientBuilder 和类似的选项类集合配置客户端。

static async Task<IClusterClient> StartClientWithRetries()
{
    _attempt = 0;
    var client = new ClientBuilder()
        .UseLocalhostClustering()
        .Configure<ClusterOptions>(options =>
        {
            options.ClusterId = "dev";
            options.ServiceId = "HelloWorldApp";
        })
        .ConfigureLogging(logging => logging.AddConsole())
        .Build();

    await client.Connect(RetryFilter);
    Console.WriteLine("Client successfully connected to silo host");
    return client;
}

private static async Task<bool> RetryFilter(Exception exception)
{
    if (exception.GetType() != typeof(SiloUnavailableException))
    {
        Console.WriteLine($"Cluster client failed to connect to cluster with unexpected error. Exception: {exception}");
        return false;
    }
    _attempt++;
    Console.WriteLine($"Cluster client attempt {_attempt} of 5 failed to connect to cluster. Exception: {exception}");
    if (_attempt > 5)
    {
        return false;
    }
    await Task.Delay(TimeSpan.FromSeconds(4));
    return true;
}
选项 用途
.UseLocalhostClustering() 与信息孤岛相同
ClusterOptions 与信息孤岛相同

在配置指南的 “客户端配置 ”部分查找有关配置客户端的更深入指南。

写一个粒子

Grain 是 Orleans 编程模型的关键基元。 它们是应用程序的构建基块 Orleans ,充当隔离、分布和持久性的原子单元。 粒度是表示应用程序实体的对象。 就像在经典 Object-Oriented 编程中一样,粒度封装实体的状态并在代码逻辑中编码其行为。 粒度可以保存彼此的引用,并通过调用通过接口公开的方法进行交互。

文档的Orleans部分阅读更多相关信息。

这是 Hello World 粒度的代码主体:

public class HelloGrain : Orleans.Grain, IHello
{
    private readonly ILogger<HelloGrain> _logger;

    public HelloGrain(ILogger<HelloGrain> logger) => _logger = logger;

    Task<string> IHello.SayHello(string greeting)
    {
        _logger.LogInformation("SayHello message received: greeting = '{Greeting}'", greeting);
        return Task.FromResult($"You said: '{greeting}', I say: Hello!");
    }
}

粒度类实现一个或多个粒度接口。 有关详细信息,请参阅 “粒度 ”部分。

public interface IHello : Orleans.IGrainWithIntegerKey
{
    Task<string> SayHello(string greeting);
}

部件如何协同工作

此编程模型基于分布式 Object-Oriented 编程的核心概念构建。 先启动 ISiloHost 。 然后,启动 OrleansClient 程序。 方法MainOrleansClient调用了启动客户端的方法StartClientWithRetries()。 将客户端传递给 DoClientWork() 方法。

static async Task DoClientWork(IClusterClient client)
{
    var friend = client.GetGrain<IHello>(0);
    var response = await friend.SayHello("Good morning, my friend!");
    Console.WriteLine($"\n\n{response}\n\n");
}

此时,OrleansClient创建对IHello Grain的引用,并通过SayHello()接口调用其IHello方法。 此调用会激活接收器中的粒度。 OrleansClient 向激活的粒度发送问候语。 程序将问候语作为对 OrleansClient 的响应,然后在控制台上显示它。

运行示例应用

若要运行示例应用,请参阅自述文件