Migreren van Orleans 3.x naar 7.0
Orleans 7.0 introduceert verschillende nuttige wijzigingen, waaronder verbeteringen in hosting, aangepaste serialisatie, onveranderbaarheid en graanabstracties.
Migratie
Bestaande toepassingen die herinneringen, streams of graanpersistentie gebruiken, kunnen niet eenvoudig worden gemigreerd naar Orleans 7,0 vanwege wijzigingen in de wijze waarop Orleans korrels en stromen worden geïdentificeerd. We zijn van plan incrementeel een migratiepad voor deze toepassingen te bieden.
Toepassingen met eerdere versies van Orleans kunnen niet soepel worden geüpgraded via een rolling upgrade naar Orleans 7.0. Daarom moet een andere upgradestrategie worden gebruikt, zoals het implementeren van een nieuw cluster en het buiten gebruik stellen van het vorige cluster. Orleans 7.0 wijzigt het wire-protocol op een niet-compatibele manier, wat betekent dat clusters geen combinatie van Orleans 7.0 hosts en hosts met eerdere versies van Orleans.
We hebben dergelijke belangrijke wijzigingen al jaren vermeden, zelfs in grote releases, dus waarom nu? Er zijn twee belangrijke redenen: identiteiten en serialisatie. Met betrekking tot identiteiten bestaan Grain- en stream-identiteiten nu uit tekenreeksen, waardoor korrels algemene typegegevens correct kunnen coderen en stromen gemakkelijker kunnen toewijzen aan het toepassingsdomein. Graantypen werden eerder geïdentificeerd met behulp van een complexe gegevensstructuur die geen algemene korrels kon vertegenwoordigen, wat leidt tot hoekgevallen. Streams werden geïdentificeerd door een string
naamruimte en een Guid sleutel, wat moeilijk was voor ontwikkelaars om toe te wijzen aan hun toepassingsdomein, maar efficiënt. Serialisatie is nu versietolerant, wat betekent dat u uw typen op bepaalde compatibele manieren kunt wijzigen, een set regels kunt volgen en erop kunt vertrouwen dat u uw toepassing kunt upgraden zonder serialisatiefouten. Dit was met name problematisch wanneer toepassingstypen in stromen of graanopslag worden bewaard. In de volgende secties worden de belangrijkste wijzigingen gedetailleerd beschreven en besproken.
Wijzigingen in verpakking
Als u een project bijwerkt naar Orleans 7.0, moet u de volgende acties uitvoeren:
- Alle clients moeten verwijzen naar Microsoft.Orleans. Client.
- Alle silo's (servers) moeten verwijzen naar Microsoft.Orleans. Server.
- Alle andere pakketten moeten verwijzen naar Microsoft.Orleans. Sdk.
- Zowel client - als serverpakketten bevatten een verwijzing naar Microsoft.Orleans. Sdk.
- Verwijder alle verwijzingen naar
Microsoft.Orleans.CodeGenerator.MSBuild
enMicrosoft.Orleans.OrleansCodeGenerator.Build
.- Vervang het gebruik door
KnownAssembly
GenerateCodeForDeclaringAssemblyAttribute. - Het
Microsoft.Orleans.Sdk
pakket verwijst naar het C#-brongeneratorpakket (Microsoft.Orleans.CodeGenerator
).
- Vervang het gebruik door
- Verwijder alle verwijzingen naar
Microsoft.Orleans.OrleansRuntime
.- De Microsoft.Orleans. Serverpakketten verwijzen naar de vervanging.
Microsoft.Orleans.Runtime
- De Microsoft.Orleans. Serverpakketten verwijzen naar de vervanging.
- Verwijder oproepen naar
ConfigureApplicationParts
. Toepassingsonderdelen zijn verwijderd. De C#-brongenerator wordt Orleans toegevoegd aan alle pakketten (inclusief de client en server) en genereert automatisch het equivalent van toepassingsonderdelen . - Vervang verwijzingen naar
Microsoft.Orleans.OrleansServiceBus
Microsoft.Orleans. Streaming.EventHubs - Als u herinneringen gebruikt, voegt u een verwijzing naar Microsoft toe.Orleans Herinneringen
- Als u streams gebruikt, voegt u een verwijzing naar Microsoft toe.Orleans Streaming
Tip
Orleans Alle voorbeelden zijn geüpgraded naar Orleans 7.0 en kunnen worden gebruikt als referentie voor de wijzigingen die zijn aangebracht. Zie Orleans het probleem #8035 dat de wijzigingen in elk voorbeeld bevat voor meer informatie.
Orleans
global using
Richtlijnen
Alle Orleans projecten verwijzen rechtstreeks of indirect naar het Microsoft.Orleans.Sdk
NuGet-pakket. Wanneer een Orleans project is geconfigureerd voor het inschakelen van impliciet gebruik (bijvoorbeeld <ImplicitUsings>enable</ImplicitUsings>
), worden de Orleans
naamruimten en Orleans.Hosting
naamruimten impliciet gebruikt. Dit betekent dat deze instructies niet nodig zijn voor uw app-code.
Zie voor meer informatie ImplicitUsings en dotnet/orleans/src/Orleans.Sdk/build/Microsoft.Orleans.Sdk.targets.
Hosting
Het ClientBuilder type is vervangen door een UseOrleansClient extensiemethode op IHostBuilder. Het IHostBuilder
type is afkomstig van het NuGet-pakket Microsoft.Extensions.Hosting . Dit betekent dat u een Orleans client kunt toevoegen aan een bestaande host zonder dat u een afzonderlijke afhankelijkheidsinjectiecontainer hoeft te maken. De client maakt tijdens het opstarten verbinding met het cluster. Zodra IHost.StartAsync dit is voltooid, wordt de client automatisch verbonden. Services die aan de IHostBuilder
service zijn toegevoegd, worden gestart in de volgorde van registratie, dus UseOrleansClient
oproep voordat aanroepen ConfigureWebHostDefaults wordt Orleans gestart voordat ASP.NET Core begint, bijvoorbeeld, zodat u direct toegang hebt tot de client vanuit uw ASP.NET Core-toepassing.
Als u het vorige ClientBuilder
gedrag wilt emuleren, kunt u een afzonderlijk HostBuilder
gedrag maken en configureren met een Orleans client.
IHostBuilder
kan een Orleans client of een Orleans silo zijn geconfigureerd. Alle silo's registreren een exemplaar van IGrainFactory en IClusterClient welke de toepassing kan gebruiken, dus het afzonderlijk configureren van een client is niet nodig en wordt niet ondersteund.
OnActivateAsync
en OnDeactivateAsync
handtekening wijzigen
Orleans staat korrels toe om code uit te voeren tijdens de activering en deactivering. Dit kan worden gebruikt om taken uit te voeren, zoals de leesstatus uit opslag- of logboeklevenscyclusberichten. In Orleans 7.0 is de handtekening van deze levenscyclusmethoden gewijzigd:
- OnActivateAsync() accepteert nu een CancellationToken parameter. Wanneer de CancellationToken activering is geannuleerd, moet het activeringsproces worden afgetrokken.
-
OnDeactivateAsync() accepteert nu een DeactivationReason parameter en een
CancellationToken
parameter. DeDeactivationReason
geeft aan waarom de activering wordt gedeactiveerd. Ontwikkelaars zullen deze informatie naar verwachting gebruiken voor logboekregistratie en diagnostische doeleinden. Wanneer hetCancellationToken
proces wordt geannuleerd, moet het deactivatieproces onmiddellijk worden voltooid. Houd er rekening mee dat omdat elke host op elk gewenst moment kan mislukken, het niet wordt aanbevolen om te vertrouwen opOnDeactivateAsync
belangrijke acties, zoals het persistent maken van de kritieke status.
Bekijk het volgende voorbeeld van een korrel die deze nieuwe methoden overschrijft:
public sealed class PingGrain : Grain, IPingGrain
{
private readonly ILogger<PingGrain> _logger;
public PingGrain(ILogger<PingGrain> logger) =>
_logger = logger;
public override Task OnActivateAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("OnActivateAsync()");
return Task.CompletedTask;
}
public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken token)
{
_logger.LogInformation("OnDeactivateAsync({Reason})", reason);
return Task.CompletedTask;
}
public ValueTask Ping() => ValueTask.CompletedTask;
}
POCO-korrels en IGrainBase
Korrels hoeven Orleans niet meer te worden overgenomen van de Grain basisklasse of een andere klasse. Deze functionaliteit wordt POCO-korrels genoemd. Voor toegang tot extensiemethoden, zoals een van de volgende:
- DeactivateOnIdle
- AsReference
- Cast
- GetPrimaryKey
- GetReminder
- GetReminders
- RegisterOrUpdateReminder
- UnregisterReminder
- GetStreamProvider
Uw graan moet implementeren IGrainBase of overnemen van Grain. Hier volgt een voorbeeld van het implementeren IGrainBase
op een graanklasse:
public sealed class PingGrain : IGrainBase, IPingGrain
{
public PingGrain(IGrainContext context) => GrainContext = context;
public IGrainContext GrainContext { get; }
public ValueTask Ping() => ValueTask.CompletedTask;
}
IGrainBase
definieert OnActivateAsync
en OnDeactivateAsync
met standaard implementaties, zodat uw graan, indien gewenst, kan deelnemen aan de levenscyclus:
public sealed class PingGrain : IGrainBase, IPingGrain
{
private readonly ILogger<PingGrain> _logger;
public PingGrain(IGrainContext context, ILogger<PingGrain> logger)
{
_logger = logger;
GrainContext = context;
}
public IGrainContext GrainContext { get; }
public Task OnActivateAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("OnActivateAsync()");
return Task.CompletedTask;
}
public Task OnDeactivateAsync(DeactivationReason reason, CancellationToken token)
{
_logger.LogInformation("OnDeactivateAsync({Reason})", reason);
return Task.CompletedTask;
}
public ValueTask Ping() => ValueTask.CompletedTask;
}
Serialisatie
De lastigste wijziging in Orleans 7.0 is de introductie van de versietolerante serializer. Deze wijziging is aangebracht omdat toepassingen zich meestal ontwikkelen en dit heeft geleid tot een aanzienlijke valkuil voor ontwikkelaars, omdat de vorige serializer het toevoegen van eigenschappen aan bestaande typen niet tolereert. Aan de andere kant was de serialisatiefunctie flexibel, waardoor ontwikkelaars de meeste .NET-typen zonder aanpassingen kunnen vertegenwoordigen, waaronder functies zoals generics, polymorfisme en verwijzingstracering. Een vervanging was lang te laat, maar gebruikers hebben nog steeds de hoogwaardige weergave van hun typen nodig. Daarom is er een vervangende serialisatiefunctie geïntroduceerd in Orleans 7.0 die ondersteuning biedt voor de hoogwaardige representatie van .NET-typen, terwijl ook typen kunnen worden ontwikkeld. De nieuwe serializer is veel efficiënter dan de vorige serializer, wat resulteert in een hogere end-to-end doorvoer van 170%.
Zie de volgende artikelen voor meer informatie, zoals deze betrekking heeft op Orleans 7.0:
Graanidentiteiten
Korrels hebben elk een unieke identiteit die bestaat uit het type en de sleutel van het graan. Eerdere versies van Orleans het gebruikte samengestelde type voor GrainId
s ter ondersteuning van graansleutels van een van beide:
Dit omvat enige complexiteit als het gaat om het omgaan met graansleutels. Graanidentiteiten bestaan uit twee onderdelen: een type en een sleutel. Het typeonderdeel bestond eerder uit een numerieke typecode, een categorie en 3 bytes aan algemene typegegevens.
Grain-identiteiten hebben nu de vorm type/key
waarin beide type
tekenreeksen key
zijn. De meest gebruikte grain-sleutelinterface is de IGrainWithStringKey. Dit vereenvoudigt de werking van graanidentiteit aanzienlijk en verbetert de ondersteuning voor algemene graantypen.
Grain-interfaces worden nu ook weergegeven met behulp van een door mensen leesbare naam, in plaats van een combinatie van een hash-code en een tekenreeksweergave van algemene typeparameters.
Het nieuwe systeem kan beter worden aangepast en deze aanpassingen kunnen worden aangestuurd door kenmerken.
-
GrainTypeAttribute(String)op een korrel
class
geeft u het type gedeelte van de graan-id op. -
DefaultGrainTypeAttribute(String) op een korrel
interface
geeft u het type van het graan op dat IGrainFactory standaard moet worden omgezet bij het verkrijgen van een korrelreferentie. Wanneer u bijvoorbeeld aanroeptIGrainFactory.GetGrain<IMyGrain>("my-key")
, retourneert de graanfactory een verwijzing naar het graan"my-type/my-key"
alsIMyGrain
het eerder genoemde kenmerk is opgegeven. - GrainInterfaceTypeAttribute(String) staat het overschrijven van de interfacenaam toe. Als u een naam expliciet opgeeft met dit mechanisme, kunt u de naam van het interfacetype wijzigen zonder de compatibiliteit met bestaande graanverwijzingen te verbreken. Houd er rekening mee dat uw interface ook de AliasAttribute in dit geval moet hebben, omdat de identiteit ervan kan worden geserialiseerd. Zie de sectie over serialisatie voor meer informatie over het opgeven van een typealias.
Zoals hierboven vermeld, kunt u de standaardnamen van de graanklasse en interface voor uw typen overschrijven, zodat u de naam van de onderliggende typen kunt wijzigen zonder de compatibiliteit met bestaande implementaties te verbreken.
Identiteiten streamen
Wanneer Orleans streams voor het eerst werden uitgebracht, konden streams alleen worden geïdentificeerd met behulp van een Guid. Dit was efficiënt in termen van geheugentoewijzing, maar het was moeilijk voor gebruikers om zinvolle stroomidentiteiten te maken, waarbij vaak enige codering of indirectie nodig was om de juiste streamidentiteit voor een bepaald doel te bepalen.
In Orleans 7.0 worden streams nu geïdentificeerd met behulp van tekenreeksen. De Orleans.Runtime.StreamIdstruct
bevat drie eigenschappen: een StreamId.Namespace, een StreamId.Keyen een StreamId.FullKey. Deze eigenschapswaarden zijn gecodeerde UTF-8-tekenreeksen. Bijvoorbeeld: StreamId.Create(String, String).
Vervanging van SimpleMessageStreams met BroadcastChannel
SimpleMessageStreams
(ook wel SMS genoemd) is verwijderd in 7.0. SMS had dezelfde interface als Orleans.Providers.Streams.PersistentStreams, maar het gedrag ervan was heel anders, omdat het afhankelijk was van directe grain-to-grain-aanroepen. Om verwarring te voorkomen, is sms verwijderd en is er een nieuwe vervangende aangeroepen Orleans.BroadcastChannel .
BroadcastChannel
ondersteunt alleen impliciete abonnementen en kan in dit geval een directe vervanging zijn. Als u expliciete abonnementen nodig hebt of de PersistentStream
interface moet gebruiken (bijvoorbeeld sms in tests tijdens het gebruik EventHub
in productie), is dit MemoryStream
de beste kandidaat voor u.
BroadcastChannel
zal hetzelfde gedrag hebben als sms, terwijl MemoryStream
het gedrag zich gedraagt als andere streamproviders. Bekijk het volgende voorbeeld van het gebruik van broadcast-kanalen:
// Configuration
builder.AddBroadcastChannel(
"my-provider",
options => options.FireAndForgetDelivery = false);
// Publishing
var grainKey = Guid.NewGuid().ToString("N");
var channelId = ChannelId.Create("some-namespace", grainKey);
var stream = provider.GetChannelWriter<int>(channelId);
await stream.Publish(1);
await stream.Publish(2);
await stream.Publish(3);
// Simple implicit subscriber example
[ImplicitChannelSubscription]
public sealed class SimpleSubscriberGrain : Grain, ISubscriberGrain, IOnBroadcastChannelSubscribed
{
// Called when a subscription is added to the grain
public Task OnSubscribed(IBroadcastChannelSubscription streamSubscription)
{
streamSubscription.Attach<int>(
item => OnPublished(streamSubscription.ChannelId, item),
ex => OnError(streamSubscription.ChannelId, ex));
return Task.CompletedTask;
// Called when an item is published to the channel
static Task OnPublished(ChannelId id, int item)
{
// Do something
return Task.CompletedTask;
}
// Called when an error occurs
static Task OnError(ChannelId id, Exception ex)
{
// Do something
return Task.CompletedTask;
}
}
}
Migratie naar MemoryStream
is eenvoudiger, omdat alleen de configuratie moet worden gewijzigd. Houd rekening met de volgende MemoryStream
configuratie:
builder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(
"in-mem-provider",
_ =>
{
// Number of pulling agent to start.
// DO NOT CHANGE this value once deployed, if you do rolling deployment
_.ConfigurePartitioning(partitionCount: 8);
});
OpenTelemetry
Het telemetriesysteem is bijgewerkt in Orleans 7.0 en het vorige systeem is verwijderd ten gunste van gestandaardiseerde .NET-API's, zoals .NET Metrics voor metrische gegevens en ActivitySource voor tracering.
Als onderdeel hiervan zijn de bestaande Microsoft.Orleans.TelemetryConsumers.*
pakketten verwijderd. We overwegen een nieuwe set pakketten te introduceren om het proces van de integratie van de metrische gegevens die worden Orleans verzonden naar uw bewakingsoplossing naar keuze te stroomlijnen. Zoals altijd zijn feedback en bijdragen welkom.
Het dotnet-counters
hulpprogramma bevat prestatiebewaking voor ad-hocstatusbewaking en prestatieonderzoek op het eerste niveau. Voor Orleans tellers kan het hulpprogramma dotnet-counters worden gebruikt om ze te bewaken:
dotnet counters monitor -n MyApp --counters Microsoft.Orleans
Op dezelfde manier kunnen metrische gegevens van OpenTelemetry de Microsoft.Orleans
meters toevoegen, zoals wordt weergegeven in de volgende code:
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics
.AddPrometheusExporter()
.AddMeter("Microsoft.Orleans"));
Als u gedistribueerde tracering wilt inschakelen, configureert u OpenTelemetry, zoals wordt weergegeven in de volgende code:
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService(serviceName: "ExampleService", serviceVersion: "1.0"));
tracing.AddAspNetCoreInstrumentation();
tracing.AddSource("Microsoft.Orleans.Runtime");
tracing.AddSource("Microsoft.Orleans.Application");
tracing.AddZipkinExporter(options =>
{
options.Endpoint = new Uri("http://localhost:9411/api/v2/spans");
});
});
In de voorgaande code is OpenTelemetry geconfigureerd voor het bewaken van:
Microsoft.Orleans.Runtime
Microsoft.Orleans.Application
Als u activiteit wilt doorgeven, roept u het volgende aan AddActivityPropagation:
builder.Host.UseOrleans((_, clientBuilder) =>
{
clientBuilder.AddActivityPropagation();
});
Functies van kernpakket herstructureren in afzonderlijke pakketten
In Orleans 7.0 hebben we geprobeerd extensies te factoreren in afzonderlijke pakketten die niet afhankelijk Orleans.Corezijn van . Orleans.StreamingDat wil zeggen, Orleans.Remindersen Orleans.Transactions zijn gescheiden van de kern. Dit betekent dat deze pakketten volledig betalen voor wat u gebruikt en dat er geen code in de kern van Orleans is toegewezen aan deze functies. Dit verkleint de kern-API-oppervlakte en assemblygrootte, vereenvoudigt de kern en verbetert de prestaties. Met betrekking tot prestaties vereisten transacties in Orleans eerder bepaalde code die voor elke methode werd uitgevoerd om potentiële transacties te coördineren. Dat is sindsdien verplaatst naar per methode.
Dit is een wijziging die fouten maakt in compilatie. Mogelijk hebt u bestaande code die communiceert met herinneringen of streams door methoden aan te roepen die eerder zijn gedefinieerd in de Grain basisklasse, maar nu uitbreidingsmethoden zijn. Dergelijke aanroepen die niet opgeven this
(bijvoorbeeld GetReminders) moeten worden bijgewerkt om (bijvoorbeeldthis
) op te nemen this.GetReminders()
omdat extensiemethoden moeten worden gekwalificeerd. Er wordt een compilatiefout weergegeven als u deze aanroepen niet bijwerkt en de vereiste codewijziging mogelijk niet duidelijk is als u niet weet wat er is gewijzigd.
Transactieclient
Orleans7.0 introduceert een nieuwe abstractie voor de coördinatie van transacties. Orleans.ITransactionClient Voorheen konden transacties alleen worden gecoördineerd door korrels. Met ITransactionClient
, dat beschikbaar is via afhankelijkheidsinjectie, kunnen clients ook transacties coördineren zonder een tussenliggend graan nodig te hebben. In het volgende voorbeeld worden tegoeden van de ene rekening ingetrokken en in een andere transactie in een andere rekening in rekening gebracht. Deze code kan worden aangeroepen vanuit een graan of van een externe client die de ITransactionClient
afhankelijkheidsinjectiecontainer heeft opgehaald.
await transactionClient.RunTransaction(
TransactionOption.Create,
() => Task.WhenAll(from.Withdraw(100), to.Deposit(100)));
Voor transacties die door de client worden gecoördineerd, moet de client de vereiste services toevoegen tijdens de configuratie:
clientBuilder.UseTransactions();
Het bankaccountvoorbeeld toont het gebruik van ITransactionClient
. Zie Orleans transacties voor meer informatie.
Reentrancy van gespreksketen
Korrels zijn één threaded en procesaanvragen één voor één van begin tot voltooiing standaard. Met andere woorden, korrels zijn niet standaard opnieuw in te voeren. Door de ReentrantAttribute aan een korrelklasse toe te voegen, kunnen meerdere aanvragen gelijktijdig worden verwerkt, op een interleaving manier, terwijl ze nog steeds met één thread worden verwerkt. Dit kan handig zijn voor korrels die geen interne status hebben of veel asynchrone bewerkingen uitvoeren, zoals het uitgeven van HTTP-aanroepen of schrijven naar een database. Er moet extra aandacht worden besteed wanneer aanvragen kunnen worden opgeslagen: het is mogelijk dat de status van een graan wordt waargenomen voordat een await
instructie is gewijzigd zodra de asynchrone bewerking is voltooid en de methode de uitvoering hervat.
Het volgende graan vertegenwoordigt bijvoorbeeld een teller. Het is gemarkeerd, waardoor meerdere aanroepen kunnen worden opgetreden Reentrant
. De Increment()
methode moet de interne teller verhogen en de waargenomen waarde retourneren. Aangezien de hoofdtekst van de Increment()
methode echter de status van het graan vóór een await
punt observeert en deze later bijwerkt, is het mogelijk dat meerdere interleaving-uitvoeringen kunnen Increment()
resulteren in een _value
kleiner dan het totale aantal Increment()
ontvangen oproepen. Dit is een fout die wordt geïntroduceerd door onjuist gebruik van reentrancy.
Het verwijderen van het ReentrantAttribute probleem is voldoende om het probleem op te lossen.
[Reentrant]
public sealed class CounterGrain : Grain, ICounterGrain
{
int _value;
/// <summary>
/// Increments the grain's value and returns the previous value.
/// </summary>
public Task<int> Increment()
{
// Do not copy this code, it contains an error.
var currentVal = _value;
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
_value = currentVal + 1;
return currentValue;
}
}
Om dergelijke fouten te voorkomen, zijn korrels standaard niet-reentrant. Het nadeel hiervan is een verminderde doorvoer voor korrels die asynchrone bewerkingen uitvoeren in hun implementatie, omdat andere aanvragen niet kunnen worden verwerkt terwijl het graan wacht tot een asynchrone bewerking is voltooid. Om dit te verlichten, Orleans biedt u verschillende opties om reentrancy in bepaalde gevallen toe te staan:
- Voor een hele klasse: door het op het ReentrantAttribute graan te plaatsen, kan elke aanvraag aan het graan worden doorgekruist met elke andere aanvraag.
- Voor een subset van methoden: door de methode voor de AlwaysInterleaveAttribute grain-interface te plaatsen, kunnen aanvragen naar die methode worden opgeslagen met elke andere aanvraag en voor aanvragen naar die methode worden geinterleaseerd door elke andere aanvraag.
- Voor een subset van methoden: door de methode voor de ReadOnlyAttribute grain-interface te plaatsen, kunnen aanvragen naar die methode worden opgeslagen met elke andere
ReadOnly
aanvraag en voor aanvragen naar die methode worden geinterleaseerd door elke andereReadOnly
aanvraag. In die zin is het een beperktere vorm vanAlwaysInterleave
. - Voor elke aanvraag binnen een oproepketen: RequestContext.AllowCallChainReentrancy() en <xref:Orleans. Runtime.RequestContext.SuppressCallChainReentrancy?displayProperty=nameWithType maakt het mogelijk om downstreamaanvragen weer terug te geven in het graan. De aanroepen retourneren beide een waarde die moet worden verwijderd tijdens het afsluiten van de aanvraag. Daarom is het juiste gebruik als volgt:
public Task<int> OuterCall(IMyGrain other)
{
// Allow call-chain reentrancy for this grain, for the duration of the method.
using var _ = RequestContext.AllowCallChainReentrancy();
await other.CallMeBack(this.AsReference<IMyGrain>());
}
public Task CallMeBack(IMyGrain grain)
{
// Because OuterCall allowed reentrancy back into that grain, this method
// will be able to call grain.InnerCall() without deadlocking.
await grain.InnerCall();
}
public Task InnerCall() => Task.CompletedTask;
Reentrancy voor oproepketens moet per graan, per gespreksketen worden gekozen. Denk bijvoorbeeld aan twee korrels, graan A & graan B. Als grain A reentrancy van gespreksketens mogelijk maakt voordat graan B wordt aangeroepen, kan grain B in die aanroep terugbellen naar grain A. Graan A kan echter niet terugbellen naar graan B als grain B ook geen reentrancy van de oproepketen heeft ingeschakeld. Het is per graan, per gespreksketen.
Korrels kunnen ook de reentrancy-informatie van gespreksketens onderdrukken door een oproepketen af te stromen met behulp van using var _ = RequestContext.SuppressCallChainReentrancy()
. Hiermee voorkomt u dat volgende aanroepen opnieuw worden uitgevoerd.
ADO.NET migratiescripts
Als u compatibiliteit met clustering, persistentie en herinneringen die afhankelijk zijn van ADO.NET, wilt doorsturen Orleans , hebt u het juiste SQL-migratiescript nodig:
Selecteer de bestanden voor de gebruikte database en pas ze in volgorde toe.