Teilen über


Anforderungskontext

Der RequestContext ist ein Orleans-Feature, mit dem Anwendungsmetadaten, z. B. eine Ablaufverfolgungs-ID, mit Anforderungen übertragen werden können. Anwendungsmetadaten können auf dem Client hinzugefügt werden. Sie werden mit Orleans-Anforderungen an das empfangende Grain übertragen. Das Feature wird von einer öffentlichen statischen Klasse, RequestContext, im Orleans-Namespace implementiert. Diese Klasse macht zwei einfache Methoden verfügbar:

void Set(string key, object value)

Die vorherige API wird verwendet, um einen Wert im Anforderungskontext zu speichern. Der Wert kann ein beliebiger serialisierbarer Typ sein.

object Get(string key)

Die vorherige API wird verwendet, um einen Wert aus dem aktuellen Anforderungskontext abzurufen.

Der Sicherungsspeicher für RequestContext ist asynchron-lokal. Wenn ein Aufrufer (egal ob clientseitig oder innerhalb von Orleans) eine Anforderung sendet, wird der Inhalt des RequestContext des Aufrufers in die Orleans-Nachricht für die Anforderung aufgenommen. Wenn der Graincode die Anforderung empfängt, sind diese Metadaten vom lokalen RequestContext aus zugänglich. Wenn der Graincode den RequestContext nicht ändert, erhält jedes Grain, das er anfordert, die gleichen Metadaten usw.

Anwendungsmetadaten werden auch beibehalten, wenn Sie eine zukünftige Berechnung mithilfe von StartNew oder ContinueWith planen. In beiden Fällen wird die Fortsetzung mit denselben Metadaten ausgeführt, die dem Planungscode zum Zeitpunkt der Planung der Berechnung vorlagen (d. h. das System erstellt eine Kopie der aktuellen Metadaten und gibt sie an die Fortsetzung weiter, sodass Änderungen nach dem Aufruf von StartNew oder ContinueWith für die Fortsetzung nicht sichtbar sind).

Wichtig

Die Metadaten der Anwendung fließen nicht mit den Antworten zurück, d. h. Code, der als Folge einer empfangenen Antwort ausgeführt wird, entweder innerhalb einer ContinueWith-Fortsetzung oder nach einem Aufruf von Task.Wait() oder GetValue, wird immer noch innerhalb des aktuellen Kontexts ausgeführt, der durch die ursprüngliche Anforderung festgelegt wurde.

Um beispielsweise eine Ablaufverfolgungs-ID im Client auf einen neuen Guidfestzulegen, rufen Sie Folgendes auf:

RequestContext.Set("TraceId", Guid.NewGuid());

Innerhalb von Graincode (oder anderem Code, der innerhalb von Orleans auf einem Planerthread ausgeführt wird) kann die Ablaufverfolgungs-ID der ursprünglichen Clientanforderung verwendet werden, z. B. beim Schreiben eines Protokolls:

Logger.LogInformation(
    "Currently processing external request {TraceId}",
    RequestContext.Get("TraceId"));

Zwar kann jede serialisierbare Datei object als Anwendungsmetadaten gesendet werden, es ist jedoch erwähnenswert, dass große oder komplexe Objekte den Zeitaufwand für die Serialisierung von Nachrichten erheblich beeinträchtigen können. Aus diesem Grund wird die Verwendung von einfachen Typen (Zeichenfolgen, GUIDs oder numerische Typen) empfohlen.

Beispielcode für Korn

Um die Verwendung eines Anforderungskontexts zu veranschaulichen, berücksichtigen Sie den folgenden Beispielkorncode:

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);
}

Die SayHello Methode protokolliert den eingehenden greeting Parameter und ruft dann die Ablaufverfolgungs-ID aus dem Anforderungskontext ab. Wenn keine Ablaufverfolgungs-ID gefunden wird, protokolliert das Korn "Keine Ablaufverfolgungs-ID".

Beispiel für Clientcode

Der Client kann die Ablaufverfolgungs-ID im Anforderungskontext festlegen, bevor die Methode für die SayHello HelloGrain. Der folgende Clientcode veranschaulicht, wie eine Ablaufverfolgungs-ID im Anforderungskontext festgelegt und die SayHello Methode für folgendes HelloGrainaufgerufen wird:

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!

In diesem Beispiel legt der Client die Ablaufverfolgungs-ID auf "example-id-set-by-client" fest, bevor die SayHello Methode für die HelloGrain. Das Korn ruft die Ablaufverfolgungs-ID aus dem Anforderungskontext ab und protokolliert sie.