Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Среда Orleans выполнения предоставляет два механизма, таймеры и напоминания, которые позволяют указать периодическое поведение для зерен.
таймеры
Используйте таймеры для создания периодического поведения зерна, которое не обязательно должно пересекать несколько активизаций (экземпляров зерна). Таймер идентичен стандартному классу .NET System.Threading.Timer . Кроме того, таймеры подвергаются гарантиям однопоточного выполнения в рамках активации зерна, с которой они работают.
Каждая активация может иметь ноль или больше таймеров, связанных с ним. Среда выполнения выполняет каждую подпрограмму таймера в контексте выполнения связанной активации.
Использование таймера
Чтобы запустить таймер, используйте RegisterGrainTimer
метод, который возвращает ссылку IGrainTimer :
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
Чтобы отменить таймер, удалите его.
Таймер перестает срабатывать, если зерно деактивируется или происходит сбой и его силос ломается.
Важные рекомендации.
- Если включена коллекция активации, выполнение обратного вызова таймера не изменяет состояние активации с простоя на использование. Это означает, что таймер нельзя использовать для отсрочки деактивации активаций, иначе находящихся в состоянии бездействия.
- Период, передаваемый в
Grain.RegisterGrainTimer
, — это промежуток времени, проходящий с момента, когдаTask
, возвращённыйcallback
, разрешается, до момента, когда должно произойти следующее вызовыcallback
. Это не только предотвращает перекрывание последовательных вызововcallback
, но также означает, что время, необходимое для выполненияcallback
, влияет на частоту вызоваcallback
. Это важное отклонение от семантики System.Threading.Timer. - Каждый вызов
callback
доставляется в активацию в отдельном цикле и никогда не выполняется одновременно с другими циклами той же активации. - Обратные вызовы по умолчанию не чередуются. Вы можете включить чередование, установив
Interleave
вtrue
наGrainTimerCreationOptions
. - Вы можете обновить таймеры зерен, используя
Change(TimeSpan, TimeSpan)
метод на возвращаемомIGrainTimer
экземпляре. - Обратные вызовы могут поддерживать активность зерна, предотвращая сборку мусора, если период таймера относительно короткий. Включите это, установив
KeepAlive
наtrue
вGrainTimerCreationOptions
. - Обратные вызовы могут получать
CancellationToken
, который отменяется, когда таймер удаляется или зерно начинает деактивироваться. - Обратные вызовы могут удалить таймер зерна, который запустил их.
- Обратные вызовы подвергаются фильтрам вызовов.
- Обратные вызовы отображаются в распределенной трассировке при включении распределенной трассировки.
- Зерна POCO (классы зерна, которые не наследуют от
Grain
) могут регистрировать таймеры зерна, используя метод расширенияRegisterGrainTimer
.
Напоминания
Напоминания похожи на таймеры с несколькими важными различиями:
- Напоминания являются постоянными и продолжают запускаться практически во всех ситуациях (включая частичные или полные перезапуски кластера), если только явно не отменены.
- Напоминание о том, что "определения" записываются в хранилище. Однако каждое конкретное вхождение с определенным временем не сохраняется. Это имеет побочный эффект, заключающийся в том, что если кластер отключен в момент запланированного события напоминания, оно будет пропущено, и произойдет только следующее событие напоминания.
- Напоминания связаны с зерном, а не какой-либо конкретной активацией.
- Если у зерна нет активации, связанной с ним, когда срабатывает напоминание, Orleans создает активацию зерна. Если активация становится бездействуемой и деактивирована, напоминание, связанное с тем же зерном, повторно активирует зерно, когда он будет тикать дальше.
- Доставка напоминаний происходит через сообщение и подвергается той же семантике чередования, что и все остальные методы зерна.
- Не следует использовать напоминания для таймеров высокой частоты; их период должен измеряться в минутах, часах или днях.
Конфигурация
Так как напоминания являются постоянными, они полагаются на хранилище для работы. Необходимо указать, какое хранилище следует использовать, прежде чем подсистема напоминаний сможет функционировать. Это можно сделать, настроив одного из поставщиков напоминаний с помощью Use{X}ReminderService
методов расширения, где X
имя поставщика (например, UseAzureTableReminderService).
Конфигурация таблицы Azure:
// 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();
Если вы просто хотите, чтобы заполнитель напоминаний работал без необходимости настраивать учетную запись Azure или базу данных SQL, это обеспечивает реализацию системы напоминаний только для разработки:
var silo = new HostBuilder()
.UseOrleans(builder =>
{
builder.UseInMemoryReminderService();
})
.Build();
Это важно
Если у вас есть разнородный кластер, где силосы обрабатывают различные типы зерна (реализуют разные интерфейсы), каждый сило должен добавить конфигурацию для напоминаний, даже если само хранилище не обрабатывает напоминания.
Использование напоминаний
Зерно, использующее напоминания, должно реализовать метод IRemindable.ReceiveReminder.
Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
Console.WriteLine("Thanks for reminding me-- I almost forgot!");
return Task.CompletedTask;
}
Чтобы запустить напоминание, используйте Grain.RegisterOrUpdateReminder метод, который возвращает IGrainReminder объект:
protected Task<IGrainReminder> RegisterOrUpdateReminder(
string reminderName,
TimeSpan dueTime,
TimeSpan period)
-
reminderName
: это строка, которая должна однозначно идентифицировать напоминание в области контекстного зерна. -
dueTime
: указывает количество времени ожидания перед срабатыванием первого таймера. -
period
: указывает период таймера.
Так как напоминания продолжают существовать на протяжении срока службы любой отдельной активации, их необходимо отменить явно (в отличие от удаления). Отмена напоминания путем вызова Grain.UnregisterReminder:
protected Task UnregisterReminder(IGrainReminder reminder)
Объект-дескриптор reminder
, который возвращает Grain.RegisterOrUpdateReminder.
Экземпляры IGrainReminder
не гарантируются быть допустимыми за пределами срока действия активации. Если вы хотите постоянно идентифицировать напоминание, используйте строку, содержащую имя напоминания.
Если у вас есть только имя напоминания и требуется соответствующий экземпляр IGrainReminder
, вызовите метод Grain.GetReminder.
protected Task<IGrainReminder> GetReminder(string reminderName)
Решите, какой из них следует использовать
Мы рекомендуем использовать таймеры в следующих обстоятельствах:
- Если это не имеет значения (или желательно), что таймер перестает работать, когда активация деактивируется или происходят сбои.
- Точность таймера низкая (например, может быть выражена в секундах или минутах).
- Вы можете запустить обратный вызов таймера из Grain.OnActivateAsync() или при вызове метода зерна.
Рекомендуется использовать напоминания в следующих случаях:
- Когда периодическое поведение должно сохраняться после активации и при любых сбоях.
- Выполнение редких задач (например, которые можно выразить в минутах, часах или днях).
Объединение таймеров и напоминаний
Вы можете использовать сочетание напоминаний и таймеров для достижения цели. Например, если вам нужен таймер с небольшой точностью, который должен продолжать работать в ряде активаций, можно использовать напоминание, выполняющееся каждые пять минут. Его целью будет пробуждение зерна, которое перезапускает локальный таймер, возможно, потерян из-за деактивации.
Регистрация зерна марки POCO
Чтобы зарегистрировать таймер или напоминание с помощью зерна POCO, реализуйте IGrainBase интерфейс и внедрите ITimerRegistry или IReminderRegistry в конструктор зерна.
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);
}
}
}
Приведенный выше код выполняет следующие действия:
- Определяет зерно POCO, реализующее IGrainBase,
IPingGrain
и IDisposable. - Регистрирует таймер каждые 10 секунд, начиная с 3 секунд после регистрации.
- При вызове
Ping
регистрируется напоминание, которое вызывается каждый час, начиная сразу после регистрации. - Метод
Dispose
отменяет напоминание, если оно зарегистрировано.