Timers och påminnelser
Körningen Orleans innehåller två mekanismer, som kallas timers och påminnelser, som gör det möjligt för utvecklaren att ange periodiskt beteende för korn.
Timers
Timers används för att skapa periodiska kornbeteenden som inte krävs för att sträcka sig över flera aktiveringar (instansiering av kornet). En timer är identisk med standardklassen .NET System.Threading.Timer . Dessutom omfattas timers av entrådiga körningsgarantier inom den kornaktivering som de arbetar med.
Varje aktivering kan ha noll eller fler timers associerade med den. Körningen kör varje timerrutin inom körningskontexten för aktiveringen som den är associerad med.
Tidsinställd användning
Om du vill starta en timer använder du RegisterGrainTimer
metoden som returnerar en IGrainTimer referens:
protected IGrainTimer RegisterGrainTimer<TState>(
Func<TState, CancellationToken, Task> callback, // function invoked when the timer ticks
TState state, // object to pass to callback
GrainTimerCreationOptions options) // timer creation options
Om du vill avbryta timern tar du bort den.
En timer upphör att utlösas om kornet inaktiveras eller när ett fel inträffar och dess silo kraschar.
Viktiga överväganden:
- När aktiveringssamlingen är aktiverad ändrar körningen av ett timeråteranrop inte aktiveringens tillstånd från inaktivt till i bruk. Det innebär att en timer inte kan användas för att skjuta upp inaktiveringen av annars inaktiva aktiveringar.
- Den period som skickas till
Grain.RegisterGrainTimer
är den tid som passerar från det ögonblick som returnerasTask
avcallback
matchas till det ögonblick då nästa anropcallback
ska ske. Detta gör det inte bara omöjligt för efterföljande anrop attcallback
överlappa, utan gör det också så att den tidcallback
det tar att slutföra påverkar den frekvens med vilkencallback
anropas. Detta är en viktig avvikelse från semantiken System.Threading.Timeri . - Varje anrop av
callback
levereras till en aktivering på en separat tur och körs aldrig samtidigt med andra aktiverar samma aktivering. - Återanrop flätas inte samman som standard. Interleaving kan aktiveras genom att ange Interleave till true på GrainTimerCreationOptions.
- Grain timers kan uppdateras med hjälp av metoden Change(TimeSpan, TimeSpan) på den returnerade IGrainTimer-instansen.
- Återanrop kan hålla kornet aktivt, vilket förhindrar att det samlas in om tidsperioden är relativt kort. Detta kan aktiveras genom att ange KeepAlive till true på GrainTimerCreationOptions.
- Återanrop kan ta emot en CancellationToken som avbryts när timern tas bort eller när grain börjar inaktiveras.
- Återanrop kan ta bort korntimern som utlöste dem.
- Återanrop omfattas av filter för kornigt anrop.
- Återanrop visas i distribuerad spårning när distribuerad spårning är aktiverad.
- POCO-korn (kornklasser som inte ärver från Grain) kan registrera tidsinställda korn med hjälp av registerGrainTimer-tilläggsmetoden.
Påminnelser
Påminnelser liknar timers, med några viktiga skillnader:
- Påminnelser är beständiga och fortsätter att utlösas i nästan alla situationer (inklusive partiella eller fullständiga klusteromstarter) om de inte uttryckligen avbryts.
- Påminnelse om att "definitioner" skrivs till lagring. Varje specifik förekomst, med sin specifika tid, är dock inte det. Detta har sidoeffekten att om klustret är nere vid tidpunkten för en specifik påminnelse-tick, kommer det att missas och endast nästa tick i påminnelsen sker.
- Påminnelser är associerade med ett korn, inte någon specifik aktivering.
- Om ett korn inte har någon aktivering associerad med den när en påminnelse tickar skapas kornet. Om en aktivering blir inaktiv och inaktiveras, reaktivaterar en påminnelse som är associerad med samma korn korn korn när den tickar nästa.
- Påminnelseleverans sker via meddelande och omfattas av samma interleaving-semantik som alla andra kornmetoder.
- Påminnelser ska inte användas för högfrekventa timers– deras period ska mätas i minuter, timmar eller dagar.
Konfiguration
Påminnelser, som är beständiga, förlitar sig på att lagringen fungerar. Du måste ange vilken lagringsbackning som ska användas innan undersystemfunktionerna påminnelse. Detta görs genom att konfigurera en av påminnelseprovidrar via Use{X}ReminderService
tilläggsmetoder, där X
är namnet på providern, till exempel UseAzureTableReminderService.
Azure Table-konfiguration:
// TODO replace with your connection string
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var silo = new HostBuilder()
.UseOrleans(builder =>
{
builder.UseAzureTableReminderService(connectionString)
})
.Build();
SQL:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
const string invariant = "YOUR_INVARIANT";
var silo = new HostBuilder()
.UseOrleans(builder =>
{
builder.UseAdoNetReminderService(options =>
{
options.ConnectionString = connectionString; // Redacted
options.Invariant = invariant;
});
})
.Build();
Om du bara vill att en platshållarimplementering av påminnelser ska fungera utan att behöva konfigurera ett Azure-konto eller EN SQL-databas får du en implementering endast för utveckling av påminnelsesystemet:
var silo = new HostBuilder()
.UseOrleans(builder =>
{
builder.UseInMemoryReminderService();
})
.Build();
Viktigt!
Om du har ett heterogent kluster, där silon hanterar olika korntyper (implementera olika gränssnitt), måste varje silo lägga till konfigurationen för Påminnelser, även om själva silon inte hanterar några påminnelser.
Påminnelseanvändning
Ett korn som använder påminnelser måste implementera IRemindable.ReceiveReminder metoden.
Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
Console.WriteLine("Thanks for reminding me-- I almost forgot!");
return Task.CompletedTask;
}
Om du vill starta en påminnelse använder du Grain.RegisterOrUpdateReminder metoden som returnerar ett IGrainReminder objekt:
protected Task<IGrainReminder> RegisterOrUpdateReminder(
string reminderName,
TimeSpan dueTime,
TimeSpan period)
-
reminderName
: är en sträng som unikt måste identifiera påminnelsen inom omfånget för det kontextuella kornet. -
dueTime
: anger hur mycket tid det tar att vänta innan den första timern skickas. -
period
: anger tidsperioden för timern.
Eftersom påminnelser överlever livslängden för en enskild aktivering måste de uttryckligen avbrytas (i stället för att tas bort). Du avbryter en påminnelse genom att ringa Grain.UnregisterReminder:
protected Task UnregisterReminder(IGrainReminder reminder)
reminder
är det referensobjekt som returneras av Grain.RegisterOrUpdateReminder.
Instanser av IGrainReminder
är inte garanterade att vara giltiga utöver livslängden för en aktivering. Om du vill identifiera en påminnelse på ett sätt som bevaras använder du en sträng som innehåller påminnelsens namn.
Om du bara har påminnelsens namn och behöver motsvarande instans av IGrainReminder
anropar Grain.GetReminder du metoden:
protected Task<IGrainReminder> GetReminder(string reminderName)
Bestäm vilken som ska användas
Vi rekommenderar att du använder timers under följande omständigheter:
- Om det inte spelar någon roll (eller är önskvärt) att timern upphör att fungera när aktiveringen inaktiveras eller om fel inträffar.
- Timerns upplösning är liten (till exempel relativt uttrycksbar i sekunder eller minuter).
- Timerns motringning kan startas från Grain.OnActivateAsync() eller när en kornmetod anropas.
Vi rekommenderar att du använder påminnelser under följande omständigheter:
- När det periodiska beteendet behöver överleva aktiveringen och eventuella fel.
- Utföra ovanliga uppgifter (till exempel rimligt uttrycksbara i minuter, timmar eller dagar).
Kombinera timers och påminnelser
Du kan överväga att använda en kombination av påminnelser och timers för att uppnå ditt mål. Om du till exempel behöver en timer med en liten upplösning som behöver överleva mellan aktiveringar kan du använda en påminnelse som körs var femte minut, vars syfte är att väcka ett korn som startar om en lokal timer som kan ha gått förlorad på grund av inaktivering.
POCO-kornregistreringar
Om du vill registrera en timer eller påminnelse med poco-korn implementerar IGrainBase du gränssnittet och matar ITimerRegistry in eller IReminderRegistry i kornkonstruktorn.
using Orleans.Timers;
namespace Timers;
public sealed class PingGrain : IGrainBase, IPingGrain, IDisposable
{
private const string ReminderName = "ExampleReminder";
private readonly IReminderRegistry _reminderRegistry;
private IGrainReminder? _reminder;
public IGrainContext GrainContext { get; }
public PingGrain(
ITimerRegistry timerRegistry,
IReminderRegistry reminderRegistry,
IGrainContext grainContext)
{
// Register timer
timerRegistry.RegisterGrainTimer(
grainContext,
callback: static async (state, cancellationToken) =>
{
// Omitted for brevity...
// Use state
await Task.CompletedTask;
},
state: this,
options: new GrainTimerCreationOptions
{
DueTime = TimeSpan.FromSeconds(3),
Period = TimeSpan.FromSeconds(10)
});
_reminderRegistry = reminderRegistry;
GrainContext = grainContext;
}
public async Task Ping()
{
_reminder = await _reminderRegistry.RegisterOrUpdateReminder(
callingGrainId: GrainContext.GrainId,
reminderName: ReminderName,
dueTime: TimeSpan.Zero,
period: TimeSpan.FromHours(1));
}
void IDisposable.Dispose()
{
if (_reminder is not null)
{
_reminderRegistry.UnregisterReminder(
GrainContext.GrainId, _reminder);
}
}
}
Koden ovan:
- Definierar ett POCO-korn som implementerar IGrainBase,
IPingGrain
och IDisposable. - Registrerar en timer som anropas var 10:e sekund och startar 3 sekunder efter registreringen.
- När
Ping
anropas registrerar du en påminnelse som anropas varje timme och börjar omedelbart efter registreringen. - Metoden
Dispose
avbryter påminnelsen om den är registrerad.