Bagikan melalui


Dasar-dasar JournaledGrain

Biji-bijian yang tercatat berasal dari JournaledGrain<TGrainState,TEventBase>, dengan parameter jenis berikut ini:

  • TGrainState mewakili keadaan biji-bijian. Kelas ini harus memiliki konstruktor default yang publik.
  • TEventBase adalah supertipe umum untuk semua peristiwa yang dapat dinaikkan untuk biji-bijian ini dan dapat menjadi kelas atau antarmuka apa pun.

Semua objek status dan peristiwa harus dapat diserialisasikan karena penyedia konsistensi log mungkin perlu mempertahankannya dan/atau mengirimnya dalam pesan pemberitahuan.

Untuk biji-bijian yang peristiwanya adalah POCO (objek C# lama biasa), Anda dapat menggunakan JournaledGrain<TGrainState> sebagai singkatan untuk JournaledGrain<TGrainState,TEventBase>.

Membaca status biji-bijian

Untuk membaca status butir saat ini dan menentukan nomor versinya, JournaledGrain miliki properti ini:

GrainState State { get; }
int Version { get; }

Nomor versi selalu sama dengan jumlah total peristiwa yang dikonfirmasi, dan status adalah hasil dari menerapkan semua peristiwa yang dikonfirmasi ke status awal. Konstruktor GrainState default kelas menentukan status awal, yang memiliki versi 0 (karena tidak ada peristiwa yang diterapkan padanya).

Penting: Aplikasi Anda tidak boleh langsung memodifikasi objek yang dikembalikan oleh State. Ini dimaksudkan untuk membaca saja. Ketika aplikasi Anda perlu memodifikasi status, aplikasi harus melakukannya secara tidak langsung dengan menaikkan peristiwa.

Menaikkan peristiwa

Ajukan peristiwa dengan memanggil fungsi RaiseEvent. Misalnya, sebuah unit yang mewakili obrolan dapat memicu PostedEvent untuk menunjukkan bahwa pengguna telah mengirimkan sebuah postingan.

RaiseEvent(new PostedEvent()
{
    Guid = guid,
    User = user,
    Text = text,
    Timestamp = DateTime.UtcNow
});

Perhatikan bahwa RaiseEvent memulai penulisan ke penyimpanan tetapi tidak menunggu penulisan selesai. Untuk banyak aplikasi, penting untuk menunggu konfirmasi bahwa peristiwa telah dipertahankan. Dalam hal ini, selalu tindak lanjuti dengan menunggu ConfirmEvents:

RaiseEvent(new DepositTransaction()
{
    DepositAmount = amount,
    Description = description
});
await ConfirmEvents();

Perhatikan bahwa bahkan jika Anda tidak secara eksplisit memanggil ConfirmEvents, peristiwa akhirnya dikonfirmasi secara otomatis di latar belakang.

Metode transisi status

Runtime memperbarui status grain secara otomatis setiap kali peristiwa dinaikkan. Aplikasi Anda tidak perlu memperbarui status secara eksplisit setelah memicu peristiwa. Namun, aplikasi Anda masih perlu memberikan kode yang menentukan cara memperbarui status sebagai respons terhadap suatu peristiwa. Anda dapat melakukan ini dengan dua cara:

(a) Kelas GrainState dapat menerapkan satu atau beberapa Apply metode pada StateType. Biasanya, Anda membuat beberapa kelebihan beban, dan runtime memilih kecocokan terdekat untuk jenis runtime acara:

class GrainState
{
    Apply(E1 @event)
    {
        // code that updates the state
    }

    Apply(E2 @event)
    {
        // code that updates the state
    }
}

(b) Biji-bijian dapat mengambil alih TransitionState fungsi:

protected override void TransitionState(
    State state, EventType @event)
{
   // code that updates the state
}

Asumsikan metode transisi tidak memiliki efek samping selain memodifikasi objek status dan harus deterministik (jika tidak, efeknya tidak dapat diprediksi). Jika kode transisi melemparkan pengecualian, Orleans menangkapnya dan menyertakannya dalam peringatan dalam Orleans log, yang dikeluarkan oleh penyedia konsistensi log.

Ketika tepatnya runtime memanggil metode transisi tergantung pada penyedia konsistensi log yang dipilih dan konfigurasinya. Aplikasi tidak boleh mengandalkan waktu tertentu kecuali penyedia konsistensi log secara eksplisit menjaminnya.

Beberapa penyedia, seperti penyedia konsistensi log Orleans.EventSourcing.LogStorage, memutar ulang urutan kejadian setiap kali butir dimuat. Oleh karena itu, selama objek peristiwa masih dapat dideserialisasi dengan benar dari penyimpanan, Anda dapat secara radikal memodifikasi kelas GrainState dan metode perubahan. Namun, untuk penyedia lain, seperti penyedia log-konsistensi Orleans.EventSourcing.StateStorage, hanya objek GrainState yang disimpan. Dalam hal ini, Anda harus memastikan data dapat dideserialisasi secara tepat saat dibaca dari penyimpanan.

Menaikkan beberapa peristiwa

Anda dapat melakukan beberapa panggilan ke RaiseEvent sebelum memanggil ConfirmEvents:

RaiseEvent(e1);
RaiseEvent(e2);
await ConfirmEvents();

Namun, ini kemungkinan menyebabkan dua kali akses penyimpanan berturut-turut dan menimbulkan risiko bahwa unit penyimpanan gagal setelah hanya menulis peristiwa pertama. Dengan demikian, biasanya lebih baik untuk memicu beberapa kejadian sekaligus dengan:

RaiseEvents(IEnumerable<EventType> events)

Ini menjamin urutan peristiwa yang diberikan ditulis ke penyimpanan secara atomis. Perhatikan bahwa karena nomor versi selalu cocok dengan panjang urutan peristiwa, menghasilkan beberapa peristiwa menaikkan nomor versi lebih dari satu dalam satu waktu.

Mengambil urutan peristiwa

Metode berikut dari kelas dasar JournaledGrain memungkinkan aplikasi Anda untuk mengambil segmen tertentu dari urutan semua peristiwa yang dikonfirmasi:

Task<IReadOnlyList<EventType>> RetrieveConfirmedEvents(
    int fromVersion,
    int toVersion);

Namun, tidak semua penyedia konsistensi log mendukung metode ini. Jika tidak didukung, atau jika segmen urutan yang ditentukan tidak lagi tersedia, NotSupportedException akan dilemparkan.

Untuk mendapatkan semua peristiwa hingga versi terbaru yang dikonfirmasi, gunakan:

await RetrieveConfirmedEvents(0, Version);

Anda hanya dapat mengambil peristiwa yang dikonfirmasi: pengecualian dilemparkan jika toVersion lebih besar dari nilai Version properti saat ini.

Karena peristiwa yang telah dikonfirmasi tidak pernah berubah, tidak ada perlombaan yang perlu dikhawatirkan, bahkan dengan beberapa instance atau konfirmasi tertunda. Namun, dalam situasi seperti itu, nilai Version properti mungkin lebih besar pada saat await resume daripada ketika RetrieveConfirmedEvents dipanggil. Oleh karena itu, mungkin disarankan untuk menyimpan nilainya dalam variabel. Lihat juga bagian tentang Jaminan Konkurensi.