Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Voordat u code schrijft om een graanklasse te implementeren, maakt u een nieuw klassebibliotheekproject dat is gericht op .NET Standard of .NET Core (voorkeur) of .NET Framework 4.6.1 of hoger (als u .NET Standard of .NET Core niet kunt gebruiken vanwege afhankelijkheden). U kunt graaninterfaces en graanklassen definiëren in hetzelfde klassebibliotheekproject of in twee verschillende projecten voor een betere scheiding van interfaces van implementatie. In beide gevallen moeten de projecten verwijzen naar Microsoft.Orleans. Sdk NuGet-pakket.
Zie de sectie Project setup van Tutorial One – Basics voor Orleansuitgebreidere instructies.
Grain-interfaces en -klassen
Korrels communiceren met elkaar en worden van buitenaf opgeroepen door methodes te gebruiken die zijn gedeclareerd als onderdeel van hun respectieve grain-interfaces. Een graanklasse implementeert een of meer eerder gedeclareerde graaninterfaces. Alle methoden van een graaninterface moeten een Task (voor void methoden), een Task<TResult>of a ValueTask<TResult> retourneren (voor methoden die waarden van het type Tretourneren).
Hier volgt een fragment uit het voorbeeld van de Orleans aanwezigheidsservice:
public interface IPlayerGrain : IGrainWithGuidKey
{
Task<IGameGrain> GetCurrentGame(CancellationToken cancellationToken = default);
Task JoinGame(IGameGrain game, CancellationToken cancellationToken = default);
Task LeaveGame(IGameGrain game, CancellationToken cancellationToken = default);
}
public class PlayerGrain : Grain, IPlayerGrain
{
private IGameGrain _currentGame;
// Game the player is currently in. May be null.
public Task<IGameGrain> GetCurrentGame(CancellationToken cancellationToken = default)
{
return Task.FromResult(_currentGame);
}
// Game grain calls this method to notify that the player has joined the game.
public Task JoinGame(IGameGrain game, CancellationToken cancellationToken = default)
{
_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, CancellationToken cancellationToken = default)
{
_currentGame = null;
Console.WriteLine(
$"Player {GetPrimaryKey()} left game {game.GetPrimaryKey()}");
return Task.CompletedTask;
}
}
Time-out voor reactie voor graanmethoden
Met de Orleans runtime kunt u een time-out voor reactie afdwingen per grainmethode. Als een graanmethode niet binnen de time-out wordt voltooid, genereert de runtime een TimeoutException. Om een time-out voor een reactie op te leggen, voegt u ResponseTimeoutAttribute toe aan de korrelmethode-definitie van de interface. Het is van cruciaal belang om het kenmerk toe te voegen aan de definitie van de interfacemethode, niet de methode-implementatie in de graanklasse, omdat zowel de client als de silo op de hoogte moeten zijn van de time-out.
Als u de vorige PlayerGrain implementatie uitbreidt, ziet u in het volgende voorbeeld hoe u een time-out voor reactie op de LeaveGame methode kunt toepassen:
public interface IPlayerGrain : IGrainWithGuidKey
{
Task<IGameGrain> GetCurrentGame(CancellationToken cancellationToken = default);
Task JoinGame(IGameGrain game, CancellationToken cancellationToken = default);
[ResponseTimeout("00:00:05")] // 5s timeout
Task LeaveGame(IGameGrain game, CancellationToken cancellationToken = default);
}
Met de voorgaande code wordt een reactietime-out van vijf seconden ingesteld voor de LeaveGame methode. Wanneer je een wedstrijd verlaat, indien het langer dan vijf seconden duurt, wordt er een TimeoutException gegooid.
U kunt ook de time-out opgeven met behulp van TimeSpan constructorparameters:
public interface IDataProcessingGrain : IGrainWithGuidKey
{
// 2 minute timeout using hours, minutes, seconds
[ResponseTimeout(0, 2, 0)]
Task<ProcessingResult> ProcessLargeDatasetAsync(Dataset data, CancellationToken cancellationToken = default);
// 500ms timeout using TimeSpan.FromMilliseconds equivalent
[ResponseTimeout("00:00:00.500")]
Task<HealthStatus> GetHealthAsync(CancellationToken cancellationToken = default);
}
Time-out voor reactie configureren
Net als bij time-outs voor reactie van afzonderlijke graanmethoden kunt u een standaardtime-out voor reactie configureren voor alle graanmethoden. Er treedt een time-out op voor aanroepen naar graanmethoden als een antwoord niet binnen de opgegeven periode wordt ontvangen. Deze periode is standaard 30 seconden. U kunt de standaardtime-out voor reactie configureren:
- Door ResponseTimeout te configureren op ClientMessagingOptions, op een externe client.
- Door ResponseTimeout te configureren op SiloMessagingOptions op een server.
Zie Orleans of Serverconfiguratie voor meer informatie over het configureren.
Aanbevolen procedures voor time-out
Houd rekening met het volgende bij het configureren van time-outs:
- Time-outs per methode overschrijven algemene instellingen: Een ResponseTimeoutAttribute op een grain-methode heeft voorrang op de algemene ResponseTimeoutAttribute configuratie.
- Stel realistische time-outs in: Basistime-outs voor de verwachte uitvoeringstijd plus redelijke netwerklatentie. Time-outs die te kort zijn veroorzaken onnodige uitval; time-outs die te lang zijn vertragen de foutdetectie.
- Langlopende bewerkingen: Voor bewerkingen die veel tijd in beslag kunnen nemen, kunt u Orleans te gebruiken in plaats van time-outs voor onbepaalde tijd uit te breiden.
- Testen: Test het time-outgedrag in uw integratietests om ervoor te zorgen dat uw toepassing situaties soepel afhandeltTimeoutException.
Retourneert waarden van graanmethoden
Definieer een graanmethode die een waarde van het type T retourneert in een graaninterface als resultaat van een Task<TResult>.
Voor graanmethoden die niet zijn gemarkeerd met het async trefwoord, wanneer de retourwaarde beschikbaar is, retourneert u deze meestal met behulp van de volgende instructie:
public Task<SomeType> GrainMethod1()
{
return Task.FromResult(GetSomeType());
}
Definieer een graanmethode die geen waarde retourneert (effectief een ongeldige methode) in een graaninterface als het retourneren van een Task. De geretourneerde Task geeft de asynchrone uitvoering en voltooiing van de methode aan. Wanneer een 'void'-methode de uitvoering voltooit, moet de speciale waarde async worden geretourneerd voor graanmethoden die niet zijn gemarkeerd met het Task.CompletedTask trefwoord.
public Task GrainMethod2()
{
return Task.CompletedTask;
}
Een graanmethode die is gemarkeerd als async retourneert de waarde rechtstreeks:
public async Task<SomeType> GrainMethod3()
{
return await GetSomeTypeAsync();
}
Een void graanmethode die is gemarkeerd als async die geen waarde retourneert, retourneert gewoon aan het einde van de uitvoering:
public async Task GrainMethod4()
{
return;
}
Als een grain-methode de retourwaarde ontvangt van een andere asynchrone methodeaanroep (naar een grain of niet) en geen foutafhandeling voor die aanroep hoeft uit te voeren, kan deze gewoon de Task retourneren van die asynchrone aanroep.
public Task<SomeType> GrainMethod5()
{
Task<SomeType> task = CallToAnotherGrain();
return task;
}
Evenzo kan een void graanmethode een Task die door een andere oproep is geretourneerd gebruiken in plaats van erop te wachten.
public Task GrainMethod6()
{
Task task = CallToAsyncAPI();
return task;
}
ValueTask<TResult> kan worden gebruikt in plaats van Task<TResult>.
IAsyncEnumerable retourwaarden
Orleans ondersteunt het retourneren IAsyncEnumerable<T> van graanmethoden, waardoor efficiënt gegevens van een korrel naar een aanroeper kunnen worden gestreamd zonder dat de volledige resultatenset in het geheugen wordt geladen. Dit is handig voor scenario's zoals:
- Grote verzamelingen gegevens geleidelijk retourneren
- Realtime updates streamen
- Resultaten verwerken zodra ze beschikbaar komen
Een interface voor streamingkorrels definiëren
public interface IDataGrain : IGrainWithStringKey
{
// Returns a streaming sequence of items
IAsyncEnumerable<DataItem> GetAllItemsAsync();
// Can also include CancellationToken for cancellation support
IAsyncEnumerable<DataItem> GetItemsAsync(CancellationToken cancellationToken = default);
}
De streamingmethode implementeren
Gebruik de yield return instructie of retourneer een IAsyncEnumerable<T> rechtstreeks:
public class DataGrain : Grain, IDataGrain
{
public async IAsyncEnumerable<DataItem> GetAllItemsAsync()
{
for (int i = 0; i < 1000; i++)
{
// Simulate async data retrieval
var item = await FetchItemAsync(i);
yield return item;
}
}
public async IAsyncEnumerable<DataItem> GetItemsAsync(
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
int id = 0;
while (!cancellationToken.IsCancellationRequested)
{
var item = await FetchItemAsync(id++);
yield return item;
}
}
private Task<DataItem> FetchItemAsync(int id) =>
Task.FromResult(new DataItem { Id = id });
}
[GenerateSerializer]
public class DataItem
{
[Id(0)]
public int Id { get; set; }
}
De streamingmethode gebruiken
var grain = client.GetGrain<IDataGrain>("mydata");
await foreach (var item in grain.GetAllItemsAsync())
{
Console.WriteLine($"Received item: {item.Id}");
// Process each item as it arrives
await ProcessItemAsync(item);
}
Batchgrootte configureren
Orleans groepeert meerdere elementen samen om netwerkverbindingsreizen te verminderen. U kunt de batchgrootte configureren met behulp van de WithBatchSize extensiemethode:
// Request up to 50 elements per batch instead of the default 100
await foreach (var item in grain.GetAllItemsAsync().WithBatchSize(50))
{
await ProcessItemAsync(item);
}
IAsyncEnumerable versus Orleans Streams
| Eigenschap | IAsyncEnumerable | Orleans Stromen |
|---|---|---|
| Gebruiksscenario | Aanvraag-antwoordstreaming | Pub-sub berichtensysteem |
| Levensduur | Beperkt tot één aanroep | Permanente abonnementen |
| Direction | Korrel alleen voor de aanroeper | Elke producent aan elke abonnee |
| Backpressure | Built-in | Providerafhankelijk |
| Volharding | Nee. | Optioneel (afhankelijk van provider) |
Gebruik IAsyncEnumerable<T> wanneer:
- U hebt een eenvoudig aanvraag-antwoordpatroon met streamingresultaten nodig
- De aanroeper initieert de gegevensstroom en verbruikt alle resultaten
- U wilt automatische ondersteuning voor terugdruk en annulering.
Gebruik OrleansStreams wanneer:
- U hebt publish-subscribe messaging met meerdere abonnees nodig
- Abonnementen moeten de korreldeactivatie overleven
- U hebt permanente of duurzame streams nodig
Korrelverwijzingen
Een graanreferentie is een proxyobject dat dezelfde graaninterface implementeert als de overeenkomstige graanklasse. Het encapsuleert de logische identiteit (type en unieke sleutel) van de beoogde granulair object. U gebruikt granulaire verwijzingen om te communiceren met de doelgran. Elke korrelverwijzing verwijst naar één korrel (één exemplaar van de graanklasse), maar u kunt meerdere onafhankelijke verwijzingen naar hetzelfde graan maken.
Omdat een korrelreferentie de logische identiteit van de doelkorrel vertegenwoordigt, is deze onafhankelijk van de fysieke locatie van het graan en blijft deze geldig, zelfs nadat het systeem volledig opnieuw is opgestart. U kunt korrelverwijzingen zoals elk ander .NET-object gebruiken. U kunt deze doorgeven aan een methode, deze gebruiken als retourwaarde voor methoden, enzovoort, en deze zelfs opslaan in permanente opslag.
U kunt een korrelreferentie verkrijgen door de identiteit van een graan door te geven aan de IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) methode, waar T de graaninterface zich bevindt en key de unieke sleutel van het graan binnen het type is.
In de volgende voorbeelden ziet u hoe u een korrelreferentie voor de IPlayerGrain eerder gedefinieerde interface kunt verkrijgen.
Vanuit een graanklasse:
IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);
Van Orleans klantcode.
IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);
Voor meer informatie over graanverwijzingen, zie het artikel over graanverwijzingen.
Aanroep van korrelmethode
Het Orleans programmeermodel is gebaseerd op asynchrone programmering. Met behulp van de korrelreferentie uit het vorige voorbeeld voert u als volgt een aanroep van een graanmethode uit:
// Invoking a grain method asynchronously
Task joinGameTask = player.JoinGame(this, GrainCancellationToken);
// 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);
U kunt twee of meer Tasks verbinden. Met de joinbewerking wordt een nieuwe Task gemaakt die oplost wanneer alle samenstellende Tasks zijn voltooid. Dit patroon is handig wanneer een korrel meerdere berekeningen moet starten en moet wachten totdat alle berekeningen zijn voltooid voordat u doorgaat. Een front-endkorrel die een webpagina genereert die uit veel onderdelen bestaat, kan bijvoorbeeld meerdere back-endaanroepen (één voor elk onderdeel) maken en een Task voor elk resultaat ontvangen. Het graan zou dan wachten totdat al deze Tasks samenkomen. Wanneer de samengevoegde Task is opgelost, zijn de individuele Tasks voltooid en zijn alle gegevens ontvangen die nodig zijn om de webpagina op te maken.
Voorbeeld:
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.
Foutvoortplanting
Wanneer een grain-methode een uitzondering genereert, Orleans propageren die uitzondering indien nodig naar de aanroepketen over alle hosts. Om dit naar behoren te laten werken, moeten uitzonderingen serialiseerbaar zijn en Orleansmoeten hosts die de uitzondering verwerken, het uitzonderingstype beschikbaar hebben. Als er geen uitzonderingstype beschikbaar is, Orleans genereert u de uitzondering als een exemplaar van Orleans.Serialization.UnavailableExceptionFallbackException, waarbij het bericht, het type en de stacktracering van de oorspronkelijke uitzondering behouden blijven.
Uitzonderingen die worden gegenereerd op basis van graanmethoden, zorgen er niet voor dat het graan wordt gedeactiveerd, tenzij de uitzondering wordt overgenomen van Orleans.Storage.InconsistentStateException. Opslagbewerkingen worden veroorzaakt InconsistentStateException wanneer ze ontdekken dat de status van het graan in het geheugen inconsistent is met de status in de database. Afgezien van de speciale verwerking van InconsistentStateException, is dit gedrag vergelijkbaar met het gooien van een uitzondering vanuit een .NET-object: uitzonderingen zorgen er niet voor dat een object vernietigd wordt.
Virtuele methoden
Een graanklasse kan desgewenst de OnActivateAsync en OnDeactivateAsync virtuele methoden overschrijven. De Orleans runtime roept deze methoden aan bij het activeren en deactiveren van elke korrel van de klasse. Dit geeft uw graancode de kans om extra initialisatie- en opschoonbewerkingen uit te voeren. Een uitzondering die door OnActivateAsync is gegenereerd, doet het activeringsproces mislukken.
Hoewel OnActivateAsync (indien overschreven) altijd wordt aangeroepen als onderdeel van het korrelactiveringsproces, OnDeactivateAsync wordt niet gegarandeerd in alle situaties aangeroepen (bijvoorbeeld in geval van een serverfout of andere abnormale gebeurtenissen). Daarom moeten uw toepassingen niet afhankelijk zijn OnDeactivateAsync van het uitvoeren van kritieke bewerkingen, zoals persistente statuswijzigingen. Gebruik deze alleen voor bewerkingen met de beste inspanning.