Testen Sie Wiederholungen und Timeouts in .NET Apps, die Microsoft.Extensions.Http.Resilience verwenden.

Tip

Neu beim Drosseln? Erfahren Sie was Throttling ist und wie Sie damit umgehen.

Auf einen Blick
Ziel: Vergewissern Sie sich, dass Ihr .NET-HTTP-Resilienzhandler Wiederholungen ausführt, Backoff verwendet und Zeitüberschreitungen wie erwartet anwendet
Zeit: 15 Minuten
Plugins:GenericRandomErrorPlugin, RetryAfterPlugin, LatencyPlugin
Prerequisites:Set up Dev Proxy, eine .NET App, die Microsoft.Extensions.Http.Resilience verwendet

Sie haben AddStandardResilienceHandler() zu Ihrem HttpClient hinzugefügt. Wie wissen Sie, dass es funktioniert? Die APIs, die Sie aufrufen, schlagen selten bei Bedarf fehl, und Komponententests, die HttpMessageHandler mocken, überspringen die Ausfallsicherheitspipeline, die Sie testen möchten.

Dev Proxy befindet sich zwischen Ihrer App und der API. Sie gibt Fehler und langsame Antworten an Ihre App zurück, sodass Ihre App unverändert ausgeführt wird und der Resilienzhandler auf echte HTTP-Antworten reagiert. Sie sehen jeden Versuch in der Dev Proxy-Ausgabe.

Funktionsweise des Standardresilienzhandlers

Bevor Sie testen, sollten Sie wissen, was Sie erwartet. Mit Standardoptionen: AddStandardResilienceHandler()

Behavior Vorgabe
Wiederholungen aktiviert HTTP 500 und höher, 408, 429, HttpRequestExceptionund TimeoutRejectedException
Anzahl der Wiederholungsversuche 3, mit exponentiellem Backoff und Jitter ab 2 Sekunden
Retry-After Header Geehrt. Der Handler wartet für die von der API angeforderte Zeit.
Versuchstimeout 10 Sekunden pro Versuch
Gesamttimeout 30 Sekunden für die Anfrage, einschließlich aller Wiederholungen

Eine vollständige Liste der Strategien und deren Standardwerte finden Sie unter Standardresilienzhandler-Standardwerte.

Leiten Sie Ihre App über Dev Proxy weiter

.NET verwendet den Systemproxy. Wenn Sie also Dev Proxy starten, werden die Anforderungen Ihrer App ohne Codeänderungen abgefangen. Weitere Informationen finden Sie unter Verwenden von Dev Proxy mit .NET Anwendungen.

Vorübergehende Fehler simulieren

Erstellen Sie eine Dev Proxy-Konfiguration, die Anfragen an Ihre API mit den Fehlern fehlschlagen lässt, die der Handler erneut ausführt. In diesem Beispiel wird https://api.contoso.com verwendet. Ersetzen Sie sie durch die URL der API, die Ihre App aufruft.

Datei: devproxyrc.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/rc.schema.json",
  "plugins": [
    {
      "name": "RetryAfterPlugin",
      "enabled": true,
      "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll"
    },
    {
      "name": "GenericRandomErrorPlugin",
      "enabled": true,
      "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
      "configSection": "transientErrors"
    }
  ],
  "urlsToWatch": [
    "https://api.contoso.com/*"
  ],
  "transientErrors": {
    "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/genericrandomerrorplugin.schema.json",
    "errorsFile": "transient-errors.json",
    "rate": 50
  }
}

Caution

Fügen Sie das RetryAfterPlugin vor dem GenericRandomErrorPlugin in Ihrer Konfigurationsdatei hinzu. Wenn Sie sie danach hinzufügen, schlägt die Anforderung bei GenericRandomErrorPlugin fehl, bevor RetryAfterPlugin sie überprüfen kann.

Definieren Sie in der Fehlerdatei eine Drosselungsantwort und zwei Serverfehler. Der @dynamic Wert legt den Retry-After Header fest und teilt RetryAfterPlugin mit, dass Ihre App so lange wartet, bevor sie die API erneut aufruft.

Datei: transient-errors.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/genericrandomerrorplugin.errorsfile.schema.json",
  "errors": [
    {
      "request": {
        "url": "https://api.contoso.com/*"
      },
      "responses": [
        {
          "statusCode": 429,
          "headers": [
            {
              "name": "Retry-After",
              "value": "@dynamic"
            }
          ]
        },
        {
          "statusCode": 500
        },
        {
          "statusCode": 503
        }
      ]
    }
  ]
}

Starten Sie Dev Proxy, und führen Sie Ihre App aus.

devproxy --config-file devproxyrc.json

Bei einer Fehlerrate von 50% sind die meisten Anfragen nach einem oder zwei Wiederholungsversuchen erfolgreich. Überprüfen Sie in der Dev Proxy-Ausgabe Folgendes:

  • Nach einer 429-Antwort kommt der nächste Versuch an dieselbe URL nach der Retry-After Zeit. Dev Proxy verwendet standardmäßig 5 Sekunden. Wenn Ihre App die API zu früh aufruft, meldet RetryAfterPlugin dies und drosselt die Anfrage.
  • Ihre App unternimmt nicht mehr Versuche, als Sie konfiguriert haben.
  • Anfragen, die Sie nicht wiederholen möchten, z. B. eine POST, die einen Datensatz erstellt, werden nur einmal gesendet. Um sie auszuschließen, rufen Sie options.Retry.DisableForUnsafeHttpMethods() an oder options.Retry.DisableFor(...).

Testen, was passiert, wenn keine Wiederholungsversuche mehr übrig sind

Wiederholungsversuche blenden kurze Fehler aus. Sie müssen auch wissen, was Ihre App tut, wenn die API immer wieder fehlschlägt. Starten Sie Dev Proxy mit einer Fehlerrate von 100%:

devproxy --config-file devproxyrc.json --failure-rate 100

Dev Proxy zeigt vier Versuche für jede Anfrage an: die ursprüngliche Anfrage und 3 Wiederholungsversuche. Nach dem letzten Wiederholen wirft der Standardhandler keine Ausnahme. Sie gibt Ihrem Code die letzte Fehlerantwort zurück. Überprüfen Sie, was Ihre App damit macht. Beispielsweise löst EnsureSuccessStatusCode() eine HttpRequestException-Ausnahme aus, und GetStringAsync() löst ebenfalls eine Ausnahme aus. Stellen Sie sicher, dass Ihre App eine nützliche Meldung anzeigt oder auf eine Alternative zurückgreift, anstatt abzustürzen oder einen generischen Fehler anzuzeigen.

Test-Timeouts

Langsame APIs lösen im Handler einen anderen Codepfad aus. Verwenden Sie zum Testen das LatencyPlugin, um Antworten über das Timeout von 10 Sekunden hinaus zu verzögern.

Datei: devproxyrc.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/rc.schema.json",
  "plugins": [
    {
      "name": "LatencyPlugin",
      "enabled": true,
      "pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
      "configSection": "slowApi"
    }
  ],
  "urlsToWatch": [
    "https://api.contoso.com/*"
  ],
  "slowApi": {
    "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/latencyplugin.schema.json",
    "minMs": 11000,
    "maxMs": 15000
  }
}

Starten Sie Dev Proxy, und führen Sie Ihre App aus. Jeder Versuch dauert länger als 10 Sekunden, sodass das Zeitlimit für den Versuch ihn abbricht und der Handler den Versuch wiederholt. Nach 30 Sekunden bricht das Gesamttimeout die Anfrage ab, und Ihr Code erhält eine TimeoutRejectedException. Überprüfen Sie, ob Ihre App sie erfasst und dem Benutzer mitteilt, was passiert ist.

Tip

Wenn Sie dieselben Szenarien mit Ihren eigenen Resilienzeinstellungen testen möchten, ändern Sie die Werte in Ihrem AddStandardResilienceHandler(options => ...) Aufruf, und führen Sie die gleichen Dev Proxy-Konfigurationen erneut aus.

Nächster Schritt

Erfahren Sie mehr über die Simulation von Throttling für eine beliebige API.

Siehe auch