Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Erstellen Sie vor dem Schreiben von Code zum Implementieren einer Kornklasse ein neues Klassenbibliotheksprojekt für .NET Standard oder .NET Core (bevorzugt) oder .NET Framework 4.6.1 oder höher (wenn Sie .NET Standard oder .NET Core aufgrund von Abhängigkeiten nicht verwenden können). Sie können Getreideschnittstellen und Kornklassen im selben Klassenbibliotheksprojekt oder in zwei verschiedenen Projekten definieren, um Schnittstellen von der Implementierung besser zu trennen. In beiden Fällen müssen die Projekte auf das NuGet-Paket Microsoft.Orleans.Sdk verweisen.
Für detailliertere Anweisungen siehe den Abschnitt Project Setup im Lernprogramm Eins – Orleans Grundlagen.
Kornschnittstellen und -klassen
Körner interagieren miteinander und werden von außen aufgerufen, indem Methoden aufgerufen werden, die als Teil ihrer jeweiligen Kornschnittstellen deklariert werden. Eine Kornklasse implementiert eine oder mehrere zuvor deklarierte Getreideschnittstellen. Alle Methoden einer Kornschnittstelle müssen eine Task (für void Methoden), eine Task<TResult>oder eine ValueTask<TResult> (für Methoden, die Werte vom Typ Tzurückgeben) zurückgeben.
Im Folgenden sehen Sie einen Auszug aus dem Beispiel für den Orleans Anwesenheitsdienst:
public interface IPlayerGrain : IGrainWithGuidKey
{
Task<IGameGrain> GetCurrentGame();
Task JoinGame(IGameGrain game);
Task LeaveGame(IGameGrain game);
}
public class PlayerGrain : Grain, IPlayerGrain
{
private IGameGrain _currentGame;
// Game the player is currently in. May be null.
public Task<IGameGrain> GetCurrentGame()
{
return Task.FromResult(_currentGame);
}
// Game grain calls this method to notify that the player has joined the game.
public Task JoinGame(IGameGrain game)
{
_currentGame = game;
Console.WriteLine(
$"Player {GetPrimaryKey()} joined game {game.GetPrimaryKey()}");
return Task.CompletedTask;
}
// Game grain calls this method to notify that the player has left the game.
public Task LeaveGame(IGameGrain game)
{
_currentGame = null;
Console.WriteLine(
$"Player {GetPrimaryKey()} left game {game.GetPrimaryKey()}");
return Task.CompletedTask;
}
}
Antwort-Timeout für Grain-Methoden
Die Orleans-Laufzeit erlaubt es Ihnen, ein Antwort-Timeout pro Grain-Methode zu erzwingen. Wenn eine Kornmethode nicht innerhalb des Timeouts abgeschlossen ist, löst die Laufzeit ein TimeoutException. Um ein Antworttimeout zu erzwingen, fügen Sie die ResponseTimeoutAttribute zur Definition der Grain-Methode in der Schnittstelle hinzu. Es ist wichtig, das Attribut zur Schnittstellenmethodendefinition und nicht zur Methodenimplementierung in der Grain-Klasse hinzuzufügen, da sowohl der Client als auch das Silo das Timeout kennen müssen.
Im folgenden PlayerGrain Beispiel wird gezeigt, wie Sie einen Antwort-Timeout für die LeaveGame-Methode auferlegen.
public interface IPlayerGrain : IGrainWithGuidKey
{
Task<IGameGrain> GetCurrentGame();
Task JoinGame(IGameGrain game);
[ResponseTimeout("00:00:05")] // 5s timeout
Task LeaveGame(IGameGrain game);
}
Der vorherige Code legt ein Antworttimeout von fünf Sekunden für die LeaveGame Methode fest. Wenn ein Spiel verlassen wird, wird ein TimeoutException geworfen, wenn es länger als fünf Sekunden dauert.
Konfigurieren des Antwort-Timeouts
Ähnlich wie bei einzelnen Getreidemethoden-Antworttimeouts können Sie ein Standardzeitlimit für die Antwort für alle Kornmethoden konfigurieren. Aufrufe von Grain-Methoden werden zeitlich begrenzt, wenn eine Antwort nicht innerhalb des angegebenen Zeitraums empfangen wird. Dieser Zeitraum beträgt standardmäßig 30 Sekunden. Sie können das Standardmäßige Antworttimeout konfigurieren:
- Durch das Konfigurieren von ResponseTimeout auf ClientMessagingOptions bei einem externen Client.
- Durch Konfigurieren ResponseTimeout auf SiloMessagingOptionseinem Server.
Weitere Informationen zum Konfigurieren Orleansfinden Sie unter Clientkonfiguration oder Serverkonfiguration.
Zurückgeben von Werten aus Getreidemethoden
Definieren Sie eine Kornmethode, die einen Wert vom Typ T in einer Kornschnittstelle zurückgibt, wie ein Task<T>.
Normalerweise geben Sie den Rückgabewert für Grain-Methoden, die nicht mit dem async-Schlüsselwort gekennzeichnet sind, mit der folgenden Anweisung zurück, wenn der Rückgabewert verfügbar ist.
public Task<SomeType> GrainMethod1()
{
return Task.FromResult(GetSomeType());
}
Definieren Sie eine Kornmethode, die keinen Wert (effektiv eine void-Methode) in einer Kornschnittstelle zurückgibt, als ein Task. Der zurückgegebene Wert gibt die asynchrone Task Ausführung und den Abschluss der Methode an. Für "grain"-Methoden, die nicht mit dem async Schlüsselwort gekennzeichnet sind, muss der spezielle Wert Task.CompletedTask zurückgegeben werden, sobald eine "void"-Methode ihre Ausführung abgeschlossen hat.
public Task GrainMethod2()
{
return Task.CompletedTask;
}
Eine kornweise markierte async Methode gibt den Wert direkt zurück:
public async Task<SomeType> GrainMethod3()
{
return await GetSomeTypeAsync();
}
Eine void Kornmethode, die als async markiert ist und keinen Wert zurückgibt, beendet einfach am Ende ihrer Ausführung.
public async Task GrainMethod4()
{
return;
}
Wenn eine Kornmethode den Rückgabewert von einem anderen asynchronen Methodenaufruf (zu einem Korn oder nicht) empfängt und keine Fehlerbehandlung für diesen Aufruf ausführen muss, kann sie einfach den Task von diesem asynchronen Aufruf empfangenen Wert zurückgeben:
public Task<SomeType> GrainMethod5()
{
Task<SomeType> task = CallToAnotherGrain();
return task;
}
In ähnlicher Weise kann eine void-Methode ein von einem anderen Aufruf zurückgegebenes Task zurückgeben, anstatt darauf zu warten.
public Task GrainMethod6()
{
Task task = CallToAsyncAPI();
return task;
}
ValueTask<T> kann anstelle von Task<T>.
Getreidereferenzen
Ein Kornverweis ist ein Proxyobjekt, das dieselbe Kornschnittstelle wie die entsprechende Kornklasse implementiert. Sie kapselt die logische Identität (Typ und eindeutiger Schlüssel) des Zielkorns. Sie verwenden Kornverweise, um Aufrufe an das Zielkorn zu tätigen. Jeder Kornverweis verweist auf ein einzelnes Korn (eine einzige Instanz der Kornklasse), Sie können jedoch mehrere unabhängige Bezüge auf dasselbe Korn erstellen.
Da ein Kornbezug die logische Identität des Zielkorns darstellt, ist es unabhängig von der physischen Position des Getreides und bleibt auch nach einem vollständigen Systemneustart gültig. Sie können Kornverweise wie jedes andere .NET-Objekt verwenden. Sie können sie an eine Methode übergeben, als Methodenrückgabewert usw. verwenden und sie sogar im permanenten Speicher speichern.
Sie können einen Kornbezug erhalten, indem Sie die Identität eines Korns an die IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) Methode übergeben, wobei T es sich um die Kornschnittstelle handelt und key der eindeutige Schlüssel des Korns innerhalb seines Typs ist.
Die folgenden Beispiele zeigen, wie Sie einen Kornbezug für die IPlayerGrain zuvor definierte Schnittstelle abrufen.
Von innen einer Getreidekategorie:
IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);
Aus Orleans Kunden-Code.
IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);
Weitere Informationen zu Kornbezügen finden Sie im Getreidereferenzartikel.
Kornmethodenaufruf
Das Orleans Programmiermodell basiert auf der asynchronen Programmierung. Hier erfahren Sie, wie Sie mithilfe des Kornverweises aus dem vorherigen Beispiel eine Kornmethode aufrufen:
// Invoking a grain method asynchronously
Task joinGameTask = player.JoinGame(this);
// The await keyword effectively makes the remainder of the
// method execute asynchronously at a later point
// (upon completion of the Task being awaited) without blocking the thread.
await joinGameTask;
// The next line will execute later, after joinGameTask has completed.
players.Add(playerId);
Sie können zwei oder mehr Tasks verbinden. Der Verknüpfungsvorgang erstellt einen neuen Task Vorgang, der aufgelöst wird, wenn der gesamte Bestandteil Tasks abgeschlossen ist. Dieses Muster ist nützlich, wenn ein Korn mehrere Berechnungen starten muss, und warten Sie, bis alle diese abgeschlossen sind, bevor Sie fortfahren. Beispielsweise kann ein Front-End-Grain, das eine Webseite mit vielen Teilen generiert, mehrere Back-End-Aufrufe tätigen (einen für jeden Teil) und für jedes Ergebnis ein Task erhalten. Das Getreide würde dann darauf warten, dass sich all diese Tasks verbinden. Wenn die verknüpfte Task abgeschlossen ist, sind die einzelnen Tasks abgeschlossen, und alle zum Formatieren der Webseite erforderlichen Daten wurden empfangen.
Beispiel:
List<Task> tasks = new List<Task>();
Message notification = CreateNewMessage(text);
foreach (ISubscriber subscriber in subscribers)
{
tasks.Add(subscriber.Notify(notification));
}
// WhenAll joins a collection of tasks, and returns a joined
// Task that will be resolved when all of the individual notification Tasks are resolved.
Task joinedTask = Task.WhenAll(tasks);
await joinedTask;
// Execution of the rest of the method will continue
// asynchronously after joinedTask is resolve.
Fehlerverteilung
Wenn eine Grain-Methode eine Ausnahme auslöst, propagiert Orleans diese Ausnahme im Aufrufstapel nach oben, über Hosts hinweg, falls notwendig. Damit dies wie beabsichtigt funktioniert, müssen Ausnahmen serialisierbar sein Orleans, und Hosts, die die Ausnahme behandeln, müssen den Ausnahmetyp verfügbar haben. Wenn kein Ausnahmetyp verfügbar ist, wirft Orleans die Ausnahme als Instanz von Orleans.Serialization.UnavailableExceptionFallbackException, wobei die Nachricht, der Typ und die Stapelablaufverfolgung der ursprünglichen Ausnahme beibehalten werden.
Ausnahmen, die von Grain-Methoden ausgelöst werden, bewirken nicht, dass das Grain deaktiviert wird, es sei denn, die Ausnahme erbt von Orleans.Storage.InconsistentStateException. Speichervorgänge werfen InconsistentStateException, wenn sie feststellen, dass der In-Memory-Zustand des Grain mit dem Zustand in der Datenbank inkonsistent ist. Abgesehen von der speziellen Behandlung InconsistentStateExceptionist dieses Verhalten dem Auslösen einer Ausnahme von .NET-Objekten ähnlich: Ausnahmen bewirken nicht, dass ein Objekt zerstört wird.
Virtuelle Methoden
Eine Klasse kann optional die OnActivateAsync- und OnDeactivateAsync-virtuellen Methoden überschreiben. Die Orleans Laufzeit ruft diese Methoden bei Aktivierung und Deaktivierung jedes Grain der Klasse auf. Dadurch hat Ihr Grain-Code die Möglichkeit, zusätzliche Initialisierungs- und Bereinigungsvorgänge auszuführen. Eine von OnActivateAsync ausgelöste Ausnahme lässt den Aktivierungsprozess fehlschlagen.
Während OnActivateAsync (wenn überschrieben) immer als Teil des Aktivierungsprozesses aufgerufen wird, ist nicht garantiert, dass OnDeactivateAsync in allen Situationen aufgerufen wird (z. B. bei einem Serverausfall oder anderen Anomalien). Aus diesem Grund sollten Ihre Anwendungen sich nicht auf OnDeactivateAsync die Durchführung kritischer Vorgänge verlassen, z. B. beibehaltene Zustandsänderungen. Verwenden Sie sie nur für Best-Effort-Vorgänge.