Контекст запроса
Это RequestContext Orleans функция, которая позволяет метаданным приложения, таким как идентификатор трассировки, передавать запросы. Метаданные приложения могут быть добавлены на клиент; он будет передаваться с 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
по-прежнему будет выполняться в текущем контексте, заданном исходным запросом.
Например, чтобы задать идентификатор трассировки в клиенте, Guid
необходимо вызвать:
RequestContext.Set("TraceId", Guid.NewGuid());
В коде зерна (или другом коде, который выполняется в Orleans потоке планировщика), можно использовать идентификатор трассировки исходного клиентского запроса, например при написании журнала:
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
параметр, а затем извлекает идентификатор трассировки из контекста запроса. Если идентификатор трассировки не найден, журналы зерна "Без идентификатора трассировки".
Пример кода клиента
Клиент может задать идентификатор трассировки в контексте запроса перед вызовом SayHello
метода в объекте HelloGrain
. В следующем клиентском коде показано, как задать идентификатор трассировки в контексте запроса и вызвать метод в SayHello
HelloGrain
следующем коде:
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!
В этом примере клиент задает идентификатор трассировки на "example-id-set-by-client" перед вызовом SayHello
метода в объекте HelloGrain
. Оно извлекает идентификатор трассировки из контекста запроса и записывает его в журнал.