NATS: 自定义服务 (Service)
使用 NATS 服务框架来创建服务会变得非常简单,基于 NATS 的服务框架,NAST 的客户端库可以更简单的构建、服务发现和监控服务。服务框架自动将所有的订阅归类到一个队列组中,提供构建基于层次化的主题功能和对应的处理器。
不需要其它的负担,库提供自动化的服务发现和状态报告,通过 NATS CLI 提供的 micro
命令,可以简单地查询和报告所有使用该框架的服务。
NATS 本身提供了同步访问的 Request 模式,这里的服务与它类似,发送请求还是 Request,不过这里是通过提供一个处理器来对收到的数据直接进行加工,并返回结果。
1. 项目准备
示例项目的使用了 .NET 的日志支持,它直接将日志输出到 Console 控制台中。所以需要在项目创建之后,添加相应的 NuGet 包。
> dotnet add package NATS.Net
> dotnet add package NATS.Client.Serializers.Json
> dotnet add package Microsoft.Extensions.Logging.Console
创建日志器实例
using System;
using Microsoft.Extensions.Logging;
using NATS.Client.Core;
using NATS.Client.Serializers.Json;
using NATS.Client.Services;
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger("NATS-by-Example");
创建 NATS 服务管理
var url = Environment.GetEnvironmentVariable("NATS_URL") ?? "127.0.0.1:4222";
var opts = new NatsOpts
{
Url = url,
LoggerFactory = loggerFactory,
SerializerRegistry = NatsJsonSerializerRegistry.Default,
Name = "NATS-by-Example",
};
await using var nats = new NatsConnection(opts);
var svc = new NatsSvcContext(nats);
2. 创建服务
实现创建服务对象,它用来管理具体的服务。
首先需要创建服务定义,每个服务需要
- 服务名称,不能包含空格
- 版本
- 描述
这里首先创建名为 minmax
的服务,
var service = await svc.AddServiceAsync(new NatsSvcConfig("minmax", "0.0.1")
{
Description = "Returns the min/max number in a request"
});
虽然此时还没有运行中的服务端点,这个服务已经可以通过 micro
协议可以被发现出来,比如通过 nats micro
命令查询。所有后台的支持,比如服务发现,PING 和状态此时都已经开始。
每当创建一个服务实例的时候,它会赋予一个唯一的标识。如果有同样名称的 minmax
运行在 NATS 的主题空间中,那么像 nats micro
这样的工具会将它们视为服务的同一个实例,而背后对该端点的订阅被作为一个队列订阅。因此,对服务的每个请求将只会发给一个端点进行处理。
3. 添加服务端点
到此为止,其实还没有对外的服务访问端点。此时的服务还是一个内部的概念。这一节开始这个问题。
当端点不支持固定的主题的时候,服务可以被加入到一个组中,这个组的名称被视为命名空间,当作主题的前缀。在下面的示例中,所有的端点都将会监听以 minmax
开始的主题。
var root = await service.AddGroupAsync("minmax");
现在为服务创建 2 个访问端点。一个用于 min
操作,另一个用于 max
操作。每个端点表示为一个订阅。参数中提供的处理器将负责实际的响应处理,分别对应 minmax.min
和 minmax.max
。
await root.AddEndpointAsync(HandleMin, "min", serializer: NatsJsonSerializer<int[]>.Default);
await root.AddEndpointAsync(HandleMax, "max", serializer: NatsJsonSerializer<int[]>.Default);
ValueTask HandleMin(NatsSvcMsg<int[]> msg)
{
var min = msg.Data.Min();
return msg.ReplyAsync(min);
}
ValueTask HandleMax(NatsSvcMsg<int[]> msg)
{
var min = msg.Data.Max();
return msg.ReplyAsync(min);
}
4. 访问服务
访问服务通过向服务端点发出请求来实现。
下面的示例中,分别向 minmax.min
和 minmax.max
发出请求,它们的前缀是服务组 minmax
。
注意对于请求没有什么特别的,就是常规的 NATS 请求。是同步访问,等待返回结果的形式。
var min = await nats.RequestAsync<int[], int>("minmax.min", new[]
{
-1, 2, 100, -2000
}, requestSerializer: NatsJsonSerializer<int[]>.Default);
logger.LogInformation("Requested min value, got {Min}", min.Data);
var max = await nats.RequestAsync<int[], int>("minmax.max", new[]
{
-1, 2, 100, -2000
}, requestSerializer: NatsJsonSerializer<int[]>.Default);
logger.LogInformation("Requested max value, got {Max}", max.Data);
logger.LogInformation("Bye!");
现在,通过 micro
管理的处理可以对请求进行处理,我们自己不需要其它额外的代码来管理它们。
就是这样啦!