Tantangan penerapan versi dan strategi mitigasi dalam Durable Functions

Penerapan versi dalam Durable Functions sangat penting karena fungsi pasti ditambahkan, dihapus, dan diubah selama masa pakai aplikasi. Durable Functions memungkinkan Anda menautkan fungsi bersama-sama dengan cara yang sebelumnya tidak mungkin, dan rantai ini memengaruhi cara Anda menangani penerapan versi.

Artikel ini membantu Anda:

Perbandingan strategi cepat

Jika Anda sudah tahu perubahan Anda mengganggu, gunakan tabel ini untuk memilih strategi mitigasi:

Strategy Paling cocok untuk Rincian
Penerapan versi orkestrasi (disarankan) Sebagian besar aplikasi dengan perubahan yang melanggar. Fitur runtime bawaan, berfungsi dengan backend penyimpanan apa pun. Lompat ke bagian
Penyebaran berdampingan Aplikasi yang tidak dapat menggunakan penerapan versi orkestrasi, atau yang memerlukan isolasi penuh melalui hub tugas atau akun penyimpanan terpisah. Lompat ke bagian
Menghentikan semua instans dalam penerbangan Prototipe dan pengembangan lokal di mana kehilangan orkestrasi dalam penerbangan dapat diterima. Lompat ke bagian

Tip

Jika Anda mencari fitur penerapan versi orkestrasi bawaan yang menyediakan isolasi versi otomatis pada tingkat runtime, lihat Penerapan versi Orkestrasi.

Important

Sebelum mengimplementasikan, periksa apakah perubahan Anda adalah perubahan yang merusak:

  • Apakah Anda mengubah nama, jenis input, atau jenis output dari fungsi aktivitas atau entitas?
  • Apakah Anda menambahkan, menghapus, atau mengurutkan ulang panggilan ke aktivitas, sub-orkestrasi, timer, atau peristiwa eksternal pada kode orkestrator?
  • Apakah Anda mengganti nama atau menghapus fungsi yang mungkin masih dipanggil orkestrasi dalam penerbangan?

Jika Anda menjawab ya untuk salah satu hal ini, gunakan salah satu strategi mitigasi di bawah ini untuk menghindari kegagalan dalam menjalankan orkestrasi.

Jenis perubahan yang merusak

Beberapa contoh perubahan yang melanggar ada. Artikel ini membahas jenis yang paling umum. Tema utama di balik semuanya adalah bahwa perubahan pada kode fungsi memengaruhi orkestrasi fungsi baru dan yang sudah ada.

Perubahan tanda tangan fungsi aktivitas atau entitas

Perubahan tanda tangan mengacu pada perubahan nama, input, atau output fungsi. Jika Anda membuat perubahan semacam ini pada fungsi aktivitas atau entitas, itu dapat merusak fungsi orkestrator apa pun yang bergantung padanya. Perilaku ini terutama berlaku untuk bahasa yang aman tipe. Jika Anda memperbarui fungsi orkestrator untuk mengakomodasi perubahan ini, Anda dapat memutus instans dalam penerbangan yang ada.

Sebagai contoh, pertimbangkan fungsi orkestrator berikut.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    await context.CallActivityAsync("Bar", result);
}

Fungsi ini mengambil hasil Foo dan meneruskannya ke Bar. Asumsikan Anda perlu mengubah nilai pengembalian Foo dari Boolean menjadi String untuk mendukung berbagai nilai hasil yang lebih luas. Hasilnya terlihat seperti ini:

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string result = await context.CallActivityAsync<string>("Foo");
    await context.CallActivityAsync("Bar", result);
}

Perubahan ini berfungsi dengan baik untuk semua instans baru fungsi orkestrator tetapi dapat merusak instans dalam penerbangan apa pun. Misalnya, pertimbangkan kasus di mana instans orkestrasi memanggil fungsi bernama Foo, mendapatkan kembali nilai boolean, lalu melakukan checkpoint. Jika perubahan tanda tangan disebarkan pada saat ini, instans yang di-checkpoint gagal segera ketika dilanjutkan dan memutar ulang panggilan ke Foo. Kegagalan ini terjadi karena hasil dalam tabel riwayat berupa nilai Boolean, tetapi kode baru mencoba mendeserialisasikannya ke dalam nilai String, yang menghasilkan perilaku tak terduga atau bahkan pengecualian runtime pada bahasa dengan tipe aman.

Contoh ini adalah salah satu dari banyak cara perubahan deklarasi fungsi yang dapat mengganggu instans yang sudah ada. Secara umum, jika orkestrator perlu mengubah cara memanggil fungsi, perubahan tersebut kemungkinan bermasalah.

Perubahan logika orkestrator

Kelas masalah penerapan versi lainnya berasal dari mengubah kode fungsi orkestrator dengan cara yang mengubah jalur eksekusi untuk instans dalam penerbangan.

Pertimbangkan fungsi orkestrator berikut:

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    await context.CallActivityAsync("Bar", result);
}

Sekarang asumsikan Anda ingin menambahkan panggilan fungsi baru antara dua panggilan fungsi yang ada.

[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool result = await context.CallActivityAsync<bool>("Foo");
    if (result)
    {
        await context.CallActivityAsync("SendNotification");
    }

    await context.CallActivityAsync("Bar", result);
}

Perubahan ini menambahkan panggilan fungsi baru ke SendNotification antara Foo dan Bar. Tidak ada perubahan tanda tangan. Masalah terjadi ketika instans yang ada melanjutkan dari panggilan ke Bar. Selama pemutaran ulang, jika panggilan asli untuk Foo dikembalikan true, maka orkestrator memutar ulang panggilan ke SendNotification, yang tidak dalam riwayat eksekusinya. Runtime mendeteksi inkonsistensi ini dan menimbulkan kesalahan orkestrasi non-deterministik karena mengalami panggilan ke SendNotification sementara yang diharapkan adalah panggilan ke Bar. Jenis masalah yang sama dapat terjadi saat menambahkan panggilan API ke operasi tahan lama lainnya, seperti membuat timer tahan lama, menunggu peristiwa eksternal, atau memanggil sub-orkestrasi.

Strategi untuk mitigasi

Warning

Menyebarkan perubahan signifikan tanpa strategi mitigasi (pendekatan "tidak melakukan apa pun") dapat menyebabkan orkestrasi gagal dengan kesalahan orkestrasi nondeterministik, terhenti tanpa batas waktu dalam status Running, atau memicu kegagalan runtime tingkat rendah yang menurunkan kinerja. Selalu gunakan salah satu strategi berikut saat menerapkan perubahan yang penting.

Tidak seperti strategi lain di bagian ini, penerapan versi orkestrasi adalah fitur runtime bawaan yang menyediakan isolasi versi otomatis. Anda tidak perlu mengelola penyebaran terpisah, hub tugas, atau akun penyimpanan. Sebaliknya, runtime itu sendiri melacak informasi versi dan memastikan bahwa instans orkestrasi diproses oleh pekerja yang kompatibel.

Dengan penerapan versi orkestrasi:

  • Setiap instance orkestrasi mendapatkan versi yang secara permanen terkait dengannya ketika dibuat.
  • Fungsi orkestrator dapat memeriksa versi dan eksekusi cabang yang sesuai, menjaga jalur kode lama dan baru di basis kode yang sama.
  • Pekerja yang menjalankan versi fungsi orkestrator yang lebih baru dapat terus menjalankan instans orkestrasi yang dibuat oleh versi yang lebih lama.
  • Runtime mencegah pekerja yang menjalankan versi fungsi orkestrator lama dari mengeksekusi orkestrasi versi yang lebih baru.

Pendekatan ini memerlukan konfigurasi minimal (string versi dan strategi pencocokan opsional) dan kompatibel dengan penyedia penyimpanan apa pun. Ini adalah strategi yang direkomendasikan untuk aplikasi yang perlu mendukung perubahan pemutusan sambil mempertahankan penyebaran nol waktu henti.

Untuk panduan konfigurasi dan implementasi terperinci, lihat Versioning orkestrasi.

Menghentikan semua instans dalam penerbangan

Opsi lain adalah menghentikan semua instans dalam penerbangan. Jika Anda menggunakan penyedia Azure Storage default untuk Durable Functions, hentikan semua instans dengan menghapus konten antrean control-queue internal dan antrean workitem-queue. Atau, hentikan aplikasi fungsi, hapus antrean ini, dan mulai ulang aplikasi. Antrean dibuat ulang secara otomatis setelah aplikasi dimulai ulang. Instans orkestrasi sebelumnya mungkin tetap dalam status "Berjalan" tanpa batas waktu, tetapi tidak mengacaukan log Anda dengan pesan kegagalan atau menyebabkan kerusakan pada aplikasi Anda. Pendekatan ini sangat ideal untuk pengembangan prototipe yang cepat, termasuk pengembangan lokal.

Warning

Pendekatan ini memerlukan akses langsung ke sumber daya penyimpanan yang mendasar dan tidak sesuai untuk semua penyedia penyimpanan yang didukung oleh Durable Functions.

Penyebaran berdampingan

Cara yang paling aman untuk memastikan bahwa perubahan besar disebarkan dengan aman adalah dengan menyebarkannya berdampingan dengan versi lama Anda. Anda dapat menggunakan salah satu teknik berikut:

  • Akun penyimpanan yang berbeda: Sebarkan semua pembaruan sebagai aplikasi fungsi baru dengan akun penyimpanan yang berbeda. Ini sepenuhnya mengisolasi status versi baru dari versi lama.
  • Hub tugas yang berbeda: Sebarkan salinan baru aplikasi fungsi dengan akun penyimpanan yang sama tetapi dengan nama hub tugas yang diperbarui. Pendekatan ini membuat artefak penyimpanan baru untuk versi baru sementara versi lama terus menggunakan artefak yang ada.

Saat melakukan penyebaran berdampingan di Azure, Anda dapat menggunakan slot penyebaran untuk menjalankan kedua versi secara bersamaan hanya dengan satu sebagai slot produksi aktif. Ketika Anda siap untuk mengekspos logika orkestrasi baru, tukar versi baru ke slot produksi.

Note

Panduan ini menggunakan istilah khusus Azure Storage, tetapi berlaku umumnya untuk semua penyedia penyimpanan Durable Functions yang didukung.

Note

Pertukaran slot penyebaran berfungsi paling baik dengan pemicu HTTP dan webhook. Untuk pemicu non-HTTP seperti antrean atau Azure Event Hubs, definisi pemicu harus berasal dari pengaturan aplikasi yang diperbarui sebagai bagian dari operasi pertukaran.

Langkah berikutnya