RequestContext这是一项Orleans功能,允许应用程序元数据(如跟踪 ID)随请求一起流动。 可以在客户端上添加应用程序元数据,并随 Orleans 请求一起流向接收端粒。 该功能由 RequestContext
命名空间中的公共静态类 Orleans 实现。 此类公开两个简单方法:
void Set(string key, object value)
使用前面的 API 在请求上下文中存储值。 该值可以是任何可序列化类型。
object Get(string key)
使用前面的 API 从当前请求上下文中检索值。
RequestContext
的后备存储是异步本地存储。 当调用方(客户端或内部 Orleans)发送请求时,调用方 RequestContext
的内容将包含在 Orleans 请求的消息中。 当粒度代码收到请求时,可以从本地 RequestContext
访问该元数据。 如果粒度代码未修改 RequestContext
,则它请求的任何粒度都会收到相同的元数据,依此等。
使用StartNew或ContinueWith计划将来的计算时,还会维护应用程序元数据。 在这两种情况下,延续操作都使用与调度代码在计算被调度时相同的元数据进行执行。 也就是说,系统会复制当前元数据并将其传递给续传,因此续传不会在调用StartNew
或ContinueWith
之后看到所做的更改。
重要
应用程序元数据不会随响应一起回流。 由于接收到响应而运行的代码(无论是在ContinueWith
延续内,还是在调用Task.Wait()或GetValue
之后)仍然运行在由原始请求设置的当前上下文中。
例如,若要将客户端中的跟踪 ID 设置为新的 Guid
,请调用:
RequestContext.Set("TraceId", Guid.NewGuid());
在粒度代码(或在计划程序线程上运行 Orleans 的其他代码)中,可以在编写日志时使用原始客户端请求的跟踪 ID:
Logger.LogInformation(
"Currently processing external request {TraceId}",
RequestContext.Get("TraceId"));
虽然您可以发送任何可序列化的object
作为应用程序元数据,但值得注意的是,大型或复杂的对象可能会显著增加消息序列化的开销。 因此,我们建议使用简单类型(字符串、GUID 或数值类型)。
示例粒度代码
为了帮助说明请求上下文的使用,请考虑以下示例粒度代码:
using GrainInterfaces;
using Microsoft.Extensions.Logging;
namespace Grains;
public class HelloGrain(ILogger<HelloGrain> logger) : Grain, IHelloGrain
{
ValueTask<string> IHelloGrain.SayHello(string greeting)
{
_logger.LogInformation("""
SayHello message received: greeting = "{Greeting}"
""",
greeting);
var traceId = RequestContext.Get("TraceId") as string
?? "No trace ID";
return ValueTask.FromResult($"""
TraceID: {traceId}
Client said: "{greeting}", so HelloGrain says: Hello!
""");
}
}
public interface IHelloGrain : IGrainWithStringKey
{
ValueTask<string> SayHello(string greeting);
}
该方法 SayHello
记录传入 greeting
参数,然后从请求上下文中检索跟踪 ID。 如果未找到跟踪 ID,则粒度会记录“无跟踪 ID”。
示例客户端代码
客户端可以在调用SayHello
HelloGrain
方法之前,在请求上下文中设置跟踪 ID。 以下客户端代码演示如何在请求上下文中设置跟踪 ID,以及如何在HelloGrain
对象上调用SayHello
方法:
using GrainInterfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using var host = Host.CreateDefaultBuilder(args)
.UseOrleansClient(clientBuilder =>
clientBuilder.UseLocalhostClustering())
.Build();
await host.StartAsync();
var client = host.Services.GetRequiredService<IClusterClient>();
var grain = client.GetGrain<IHelloGrain>("friend");
var id = "example-id-set-by-client";
RequestContext.Set("TraceId", id);
var message = await friend.SayHello("Good morning!");
Console.WriteLine(message);
// Output:
// TraceID: example-id-set-by-client
// Client said: "Good morning!", so HelloGrain says: Hello!
在此示例中,客户端将跟踪 ID 设置为“example-id-set-by-client”后,再调用 SayHello
方法 HelloGrain
。 Grain 从请求上下文中检索跟踪 ID 并将其记录下来。