Baca dalam bahasa Inggris

Bagikan melalui


Timer dan pengingat

Orleans Runtime menyediakan dua mekanisme, yang disebut timer dan pengingat, yang memungkinkan pengembang menentukan perilaku berkala untuk biji-bijian.

Timer

Timer digunakan untuk membuat perilaku biji-bijian berkala yang tidak diperlukan untuk menjangkau beberapa aktivasi (instansiasi biji-bijian). Timer identik dengan kelas .NET System.Threading.Timer standar. Selain itu, timer tunduk pada jaminan eksekusi utas tunggal dalam aktivasi biji-bijian yang mereka operasikan.

Setiap aktivasi mungkin memiliki nol atau lebih timer yang terkait dengannya. Runtime menjalankan setiap rutinitas timer dalam konteks runtime aktivasi yang terkait dengannya.

Penggunaan timer

Untuk memulai timer, gunakan RegisterGrainTimer metode , yang mengembalikan IGrainTimer referensi:

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

Untuk membatalkan timer, Anda membuangnya.

Timer berhenti memicu jika biji-bijian dinonaktifkan atau ketika kesalahan terjadi dan silonya crash.

Pertimbangan penting:

  • Saat pengumpulan aktivasi diaktifkan, eksekusi panggilan balik timer tidak mengubah status aktivasi dari menganggur menjadi sedang digunakan. Ini berarti bahwa timer tidak dapat digunakan untuk menunda pennonaktifkan aktivasi diam.
  • Periode yang diteruskan adalah Grain.RegisterGrainTimer jumlah waktu yang berlalu sejak Task dikembalikan oleh callback diselesaikan pada saat pemanggilan callback berikutnya harus terjadi. Ini tidak hanya membuatnya tidak mungkin untuk panggilan berturut-turut untuk callback tumpang tindih, tetapi juga membuatnya sehingga lamanya waktu callback yang diperlukan untuk menyelesaikan mempengaruhi frekuensi di mana callback dipanggil. Ini adalah penyimpangan penting dari semantik System.Threading.Timer.
  • Setiap pemanggilan callback dikirimkan ke aktivasi pada giliran terpisah, dan tidak pernah berjalan bersamaan dengan giliran lain pada aktivasi yang sama.
  • Panggilan balik tidak diselang-seling secara default. Interleaving dapat diaktifkan dengan mengatur Interleave ke true di GrainTimerCreationOptions.
  • Timer grain dapat diperbarui menggunakan metode Change(TimeSpan, TimeSpan) pada instans IGrainTimer yang dikembalikan.
  • Panggilan balik dapat menjaga biji-bijian tetap aktif, mencegahnya dikumpulkan jika periode timer relatif pendek. Ini dapat diaktifkan dengan mengatur KeepAlive ke true pada GrainTimerCreationOptions.
  • Panggilan balik dapat menerima CancellationToken yang dibatalkan ketika timer dibuang atau biji-bijian mulai dinonaktifkan.
  • Callback dapat membuang pengatur waktu grain yang memicu mereka.
  • Panggilan balik tunduk pada filter panggilan grain.
  • Panggilan balik terlihat dalam pelacakan terdistribusi, saat pelacakan terdistribusi diaktifkan.
  • Butir POCO (kelas biji-bijian yang tidak mewarisi dari Grain) dapat mendaftarkan timer biji-bijian menggunakan metode ekstensi RegisterGrainTimer.

Pengingat

Pengingat mirip dengan timer, dengan beberapa perbedaan penting:

  • Pengingat bersifat persisten dan terus memicu dalam hampir semua situasi (termasuk restart kluster parsial atau penuh) kecuali dibatalkan secara eksplisit.
  • Pengingat "definisi" ditulis ke penyimpanan. Namun, setiap kemunculan tertentu, dengan waktu spesifiknya, tidak. Ini memiliki efek samping bahwa jika kluster tidak berfungsi pada saat centang pengingat tertentu, itu akan terlewatkan dan hanya tanda centang pengingat berikutnya yang terjadi.
  • Pengingat dikaitkan dengan biji-bijian, bukan aktivasi tertentu.
  • Jika biji-bijian tidak memiliki aktivasi yang terkait dengannya ketika pengingat berdetak, biji-bijian dibuat. Jika aktivasi menjadi diam dan dinonaktifkan, pengingat yang terkait dengan biji-bijian yang sama mengaktifkan kembali biji-bijian ketika berdetak berikutnya.
  • Pengiriman pengingat terjadi melalui pesan dan tunduk pada semantik interleaving yang sama dengan semua metode biji-bijian lainnya.
  • Pengingat tidak boleh digunakan untuk timer frekuensi tinggi- periodenya harus diukur dalam menit, jam, atau hari.

Konfigurasi

Pengingat, menjadi persisten, mengandalkan penyimpanan untuk berfungsi. Anda harus menentukan backing penyimpanan mana yang akan digunakan sebelum fungsi subsistem pengingat. Ini dilakukan dengan mengonfigurasi salah satu penyedia pengingat melalui Use{X}ReminderService metode ekstensi, di mana X adalah nama penyedia, misalnya, UseAzureTableReminderService.

Konfigurasi Azure Table:

// 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();

Jika Anda hanya ingin implementasi pengingat tempat penampung berfungsi tanpa perlu menyiapkan akun Azure atau database SQL, maka ini memberi Anda implementasi sistem pengingat khusus pengembangan:

var silo = new HostBuilder()
    .UseOrleans(builder =>
    {
        builder.UseInMemoryReminderService();
    })
    .Build();

Penting

Jika Anda memiliki kluster heterogen, di mana silo menangani jenis butir yang berbeda (menerapkan antarmuka yang berbeda), setiap silo harus menambahkan konfigurasi untuk Pengingat, bahkan jika silo itu sendiri tidak menangani pengingat apa pun.

Penggunaan pengingat

Butir yang menggunakan pengingat harus menerapkan metode .IRemindable.ReceiveReminder

Task IRemindable.ReceiveReminder(string reminderName, TickStatus status)
{
    Console.WriteLine("Thanks for reminding me-- I almost forgot!");
    return Task.CompletedTask;
}

Untuk memulai pengingat, gunakan Grain.RegisterOrUpdateReminder metode , yang mengembalikan IGrainReminder objek:

protected Task<IGrainReminder> RegisterOrUpdateReminder(
    string reminderName,
    TimeSpan dueTime,
    TimeSpan period)
  • reminderName: adalah string yang harus mengidentifikasi pengingat secara unik dalam cakupan butir kontekstual.
  • dueTime: menentukan kuantitas waktu untuk menunggu sebelum mengeluarkan centang pewaktu pertama.
  • period: menentukan periode timer.

Karena pengingat bertahan selama masa pakai aktivasi tunggal apa pun, mereka harus dibatalkan secara eksplisit (dibandingkan dengan dibuang). Anda membatalkan pengingat dengan memanggil Grain.UnregisterReminder:

protected Task UnregisterReminder(IGrainReminder reminder)

reminder adalah objek handle yang dikembalikan oleh Grain.RegisterOrUpdateReminder.

Instans IGrainReminder tidak dijamin valid di luar masa pakai aktivasi. Jika Anda ingin mengidentifikasi pengingat dengan cara yang bertahan, gunakan string yang berisi nama pengingat.

Jika Anda hanya memiliki nama pengingat dan memerlukan instans yang sesuai dari IGrainReminder, panggil Grain.GetReminder metode :

protected Task<IGrainReminder> GetReminder(string reminderName)

Memutuskan mana yang akan digunakan

Kami menyarankan agar Anda menggunakan timer dalam keadaan berikut:

  • Jika tidak masalah (atau diinginkan) bahwa timer berhenti berfungsi ketika aktivasi dinonaktifkan atau kegagalan terjadi.
  • Resolusi timer kecil (misalnya, cukup dapat diekspresikan dalam hitungan detik atau menit).
  • Panggilan balik timer dapat dimulai dari Grain.OnActivateAsync() atau ketika metode biji-bijian dipanggil.

Kami menyarankan agar Anda menggunakan pengingat dalam keadaan berikut:

  • Ketika perilaku berkala perlu bertahan dari aktivasi dan kegagalan apa pun.
  • Melakukan tugas yang jarang terjadi (misalnya, cukup dapat diekspresikan dalam menit, jam, atau hari).

Menggabungkan timer dan pengingat

Anda mungkin mempertimbangkan untuk menggunakan kombinasi pengingat dan timer untuk mencapai tujuan Anda. Misalnya, jika Anda memerlukan timer dengan resolusi kecil yang perlu bertahan di seluruh aktivasi, Anda dapat menggunakan pengingat yang berjalan setiap lima menit, yang tujuannya adalah untuk membangunkan biji-bijian yang memulai ulang timer lokal yang mungkin hilang karena penonaktifan.

Pendaftaran biji-bijian POCO

Untuk mendaftarkan timer atau pengingat dengan butir POCO, Anda mengimplementasikan IGrainBase antarmuka dan menyuntikkan ITimerRegistry atau IReminderRegistry ke konstruktor grain.

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);
        }
    }
}

Kode sebelumnya:

  • Mendefinisikan butir POCO yang mengimplementasikan IGrainBase, IPingGrain, dan IDisposable.
  • Mendaftarkan timer yang dipanggil setiap 10 detik, dan dimulai 3 detik setelah pendaftaran.
  • Ketika Ping dipanggil, mendaftarkan pengingat yang dipanggil setiap jam, dan segera mulai mengikuti pendaftaran.
  • Metode Dispose membatalkan pengingat jika terdaftar.