Bagikan melalui


Penerapan versi orkestrasi dalam Durable Functions (Azure Functions) - pratinjau publik

Versi orkestrasi mengatasi tantangan inti dalam melakukan penyebaran perubahan pada fungsi orkestrator sambil mempertahankan model eksekusi deterministik yang diperlukan oleh Durable Functions. Tanpa fitur ini, melanggar perubahan pada logika orkestrator atau tanda tangan fungsi aktivitas akan menyebabkan instans orkestrasi dalam penerbangan gagal selama pemutaran ulang karena akan merusak persyaratan determinisme yang memastikan eksekusi orkestrasi yang andal. Fitur bawaan ini menyediakan isolasi versi otomatis dengan konfigurasi minimal. Ini tidak tergantung pada backend, sehingga aplikasi dapat menggunakannya dengan memanfaatkan salah satu penyedia penyimpanan dari Durable Function, termasuk Durable Task Scheduler.

Note

Untuk pengguna Durable Task Scheduler, jika Anda menggunakan Durable Task SDK alih-alih fungsi Durable, Anda harus merujuk ke artikel penerapan versi Durable Task SDK.

Terminology

Artikel ini menggunakan dua istilah terkait tetapi berbeda:

  • Fungsi orkestrator (atau hanya "orkestrator"): Mengacu pada kode fungsi yang menentukan logika alur kerja - templat atau cetak biru tentang bagaimana alur kerja harus dijalankan.
  • Instans orkestrasi (atau hanya "orkestrasi"): Mengacu pada eksekusi tertentu yang berjalan dari fungsi orkestrator, dengan status, ID instans, dan inputnya sendiri. Beberapa instans orkestrasi dapat berjalan bersamaan dari fungsi orkestrator yang sama.

Memahami perbedaan ini sangat penting untuk penerapan versi orkestrasi, di mana kode fungsi orkestrator berisi logika sadar versi, sementara instans orkestrasi secara permanen dikaitkan dengan versi tertentu saat dibuat.

Cara kerjanya

Fitur penerapan versi orkestrasi beroperasi pada prinsip-prinsip inti ini:

  • Asosiasi Versi: Saat instans orkestrasi dibuat, ia akan mendapatkan versi yang terkait secara permanen dengannya.

  • Eksekusi Sadar Versi: Kode fungsi orkestrator dapat memeriksa nilai versi yang terkait dengan instans orkestrasi saat ini dan memecah eksekusi sesuai dengan kebutuhan.

  • Kompatibilitas Mundur: Pekerja yang menjalankan versi orkestrator yang lebih baru dapat terus menjalankan instans orkestrasi yang dibuat oleh versi orkestrator yang lebih lama.

  • Perlindungan Terhadap Penerusan: Runtime secara otomatis mencegah pekerja yang menjalankan versi orkestrator lama agar tidak menjalankan orkestrasi yang dimulai oleh versi orkestrator baru.

Important

Versi Orkestrasi saat ini sedang dalam pratinjau publik.

Prasyarat

Sebelum menggunakan penerapan versi orkestrasi, pastikan Anda memiliki versi paket yang diperlukan untuk bahasa pemrograman Anda.

Jika Anda menggunakan bahasa non-.NET (JavaScript, Python, PowerShell, atau Java) dengan bundel ekstensi, aplikasi fungsi Anda harus mereferensikan Bundel Ekstensi versi 4.26.0 atau yang lebih baru. Konfigurasikan rentang extensionBundle dalam host.json agar versi minimal setidaknya 4.26.0, misalnya:

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.26.0, 5.0.0)"
    }
}

Lihat dokumentasi konfigurasi bundel ekstensi untuk detail tentang memilih dan memperbarui versi bundel.

Gunakan Microsoft.Azure.Functions.Worker.Extensions.DurableTask versi 1.5.0 atau yang lebih baru.

Penggunaan dasar

Kasus penggunaan yang paling umum untuk pembuatan versi orkestrasi adalah ketika Anda perlu membuat perubahan signifikan pada logika orkestrator Anda sambil menjaga instans orkestrasi yang sedang berjalan tetap menggunakan versi aslinya. Yang perlu Anda lakukan adalah memperbarui defaultVersion di Anda host.json dan memodifikasi kode orkestrator Anda untuk memeriksa versi orkestrasi dan eksekusi cabang yang sesuai. Mari kita telusuri langkah-langkah yang diperlukan.

Note

Perilaku yang dijelaskan di bagian ini menargetkan situasi yang paling umum, dan inilah yang disediakan konfigurasi default. Namun, ini dapat dimodifikasi jika diperlukan (lihat Penggunaan tingkat lanjut untuk detailnya).

Langkah 1: konfigurasi defaultVersion

Untuk mengonfigurasi versi default untuk orkestrasi, Anda perlu menambahkan atau memperbarui defaultVersion pengaturan dalam host.json file di proyek Azure Functions Anda:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>"
    }
  }
}

String versi dapat mengikuti format apa pun yang sesuai dengan strategi penerapan versi Anda:

  • Versi multi-bagian: "1.0.0", "2.1.0"
  • Penomoran sederhana: "1", "2"
  • Berbasis tanggal: "2025-01-01"
  • Format kustom: "v1.0-release"

Setelah Anda mengatur defaultVersion, semua instans orkestrasi baru akan dikaitkan secara permanen dengan versi tersebut.

Aturan perbandingan versi

Ketika strategi Strict atau CurrentOrOlder dipilih (lihat Pencocokan versi), runtime membandingkan versi instans orkestrasi dengan nilai defaultVersion pekerja menggunakan aturan berikut:

  • Versi kosong atau null diperlakukan sama.
  • Versi kosong atau null dianggap lebih lama dari versi yang ditentukan.
  • Jika kedua versi dapat diurai sebagai System.Version, CompareTo metode digunakan.
  • Jika tidak, perbandingan string yang tidak peka terhadap huruf besar/kecil dilakukan.

Langkah 2: Logika fungsi orkestrator

Untuk menerapkan logika sadar versi dalam fungsi orkestrator Anda, Anda dapat menggunakan parameter konteks yang diteruskan ke orkestrator untuk mengakses versi instans orkestrasi saat ini, yang memungkinkan Anda untuk mencabangkan logika orkestrator Anda berdasarkan versi.

Important

Saat menerapkan logika sadar versi, sangat penting untuk mempertahankan logika orkestrator yang tepat untuk versi yang lebih lama. Setiap perubahan pada rangkaian, urutan, atau tanda tangan panggilan aktivitas untuk versi yang ada dapat mengganggu pemutaran ulang deterministik dan menyebabkan orkestrasi yang sedang berlangsung gagal atau menghasilkan hasil yang salah. Jalur kode versi lama harus tetap tidak berubah setelah disebarkan.

[Function("MyOrchestrator")]
public static async Task<string> RunOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    if (context.Version == "1.0")
    {
        // Original logic for version 1.0
        ...
    }
    else if (context.Version == "2.0")
    {
        // New logic for version 2.0
        ...
    }
    ...
}

Note

Properti context.Version bersifat baca-saja dan mencerminkan versi yang secara permanen terkait dengan instans orkestrasi saat dibuat. Anda tidak dapat mengubah nilai ini selama eksekusi orkestrasi. Jika Anda ingin menentukan versi melalui cara selain host.json, Anda dapat melakukannya saat memulai instans orkestrasi dengan API klien orkestrasi (lihat Memulai orkestrasi baru dan sub-orkestrasi dengan versi tertentu).

Tip

Jika Anda baru saja mulai menggunakan versi orkestrasi dan Anda sudah memiliki orkestrasi yang sedang berjalan yang dibuat sebelum Anda menentukan defaultVersion, Anda masih dapat menambahkan pengaturan defaultVersion ke host.json Anda sekarang. Untuk semua orkestrasi yang dibuat sebelumnya, context.Version mengembalikan null (atau nilai dependen bahasa yang setara), sehingga Anda dapat menyusun logika orkestrator Anda untuk menangani warisan (versi null) dan orkestrasi versi baru yang sesuai. Berikut ini adalah nilai yang bergantung pada bahasa untuk memeriksa kasus bawaan:

  • C#: context.Version == null atau context.Version is null
  • JavaScript: context.df.version == null
  • Python: context.version is None
  • PowerShell: $null -eq $Context.Version
  • Java: context.getVersion() == null Perhatikan juga bahwa menentukan "defaultVersion": null di host.json setara dengan tidak menentukannya sama sekali.

Tip

Tergantung pada situasi Anda, Anda mungkin lebih suka bercabang pada tingkat yang berbeda. Anda dapat membuat perubahan lokal dengan tepat di mana perubahan ini diperlukan, seperti contoh yang ditunjukkan. Atau, Anda dapat bercabang pada tingkat yang lebih tinggi, bahkan di seluruh tingkat implementasi orkestrator, yang memperkenalkan beberapa duplikasi kode, tetapi dapat menjaga alur eksekusi tetap jelas. Terserah Anda untuk memilih pendekatan yang paling sesuai dengan skenario dan gaya pengkodean Anda.

Apa yang terjadi setelah penyebaran

Inilah yang diharapkan setelah Anda menyebarkan fungsi orkestrator yang diperbarui dengan logika versi baru:

  • Koeksistensi Pekerja: Pekerja yang memuat kode fungsi orkestrator baru akan mulai beroperasi, sementara beberapa pekerja dengan kode lama berpotensi masih aktif.

  • Penetapan Versi untuk Instans Baru: Semua orkestrasi dan sub-orkestrasi baru yang dibuat oleh pekerja baru akan mendapatkan versi dari defaultVersion yang ditetapkan kepada mereka.

  • Kompatibilitas Pekerja Baru: Pekerja baru akan dapat memproses orkestrasi yang baru dibuat dan orkestrasi yang sudah ada sebelumnya karena perubahan yang dilakukan di Langkah 2 dari bagian sebelumnya memastikan kompatibilitas ke belakang melalui logika percabangan yang menyadari versi.

  • Pembatasan Pekerja Lama: Pekerja lama hanya akan diizinkan untuk memproses orkestrasi dengan versi yang sama dengan atau lebih rendah dari versi yang ditentukan sendiri defaultVersion di host.json, karena mereka tidak diharapkan memiliki kode orkestrator yang kompatibel dengan versi yang lebih baru. Pembatasan ini mencegah kesalahan eksekusi dan perilaku tak terduga.

Note

Penerapan versi orkestrasi tidak memengaruhi siklus hidup pekerja. Platform Azure Functions mengelola provisi dan penonaktifan pekerja berdasarkan aturan reguler tergantung pada opsi hosting.

Contoh: Mengganti aktivitas secara berurutan

Contoh ini menunjukkan cara mengganti satu aktivitas dengan aktivitas yang berbeda di tengah urutan menggunakan penerapan versi orkestrasi.

Versi 1.0

Konfigurasi host.json:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "1.0"
    }
  }
}

Fungsi dari orkestrator:

[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var orderId = context.GetInput<string>();
    
    await context.CallActivityAsync("ValidateOrder", orderId);
    await context.CallActivityAsync("ProcessPayment", orderId);
    await context.CallActivityAsync("ShipOrder", orderId);
    
    return "Order processed successfully";
}

Versi 2.0 dengan pemrosesan diskon

Konfigurasi host.json:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "2.0"
    }
  }
}

Fungsi dari orkestrator:

using DurableTask.Core.Settings;

[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var orderId = context.GetInput<string>();

    await context.CallActivityAsync("ValidateOrder", orderId);

    if (VersioningSettings.CompareVersions(context.Version, "1.0") <= 0)
    {
        // Preserve original logic for existing instances
        await context.CallActivityAsync("ProcessPayment", orderId);
    }
    else // a higher version (including 2.0)
    {
        // New logic with discount processing (replaces payment processing)
        await context.CallActivityAsync("ApplyDiscount", orderId);
        await context.CallActivityAsync("ProcessPaymentWithDiscount", orderId);
    }
    
    await context.CallActivityAsync("ShipOrder", orderId);

    return "Order processed successfully";
}

Penggunaan tingkat lanjut

Untuk skenario penerapan versi yang lebih canggih, Anda dapat mengonfigurasi pengaturan lain untuk mengontrol bagaimana runtime menangani kecocokan versi dan ketidakcocokan.

Tip

Gunakan konfigurasi default (CurrentOrOlder dengan Reject) untuk sebagian besar skenario untuk mengaktifkan penyebaran bergulir yang aman sambil mempertahankan status orkestrasi selama transisi versi. Sebaiknya lanjutkan dengan konfigurasi tingkat lanjut hanya jika Anda memiliki persyaratan khusus yang tidak dapat dipenuhi dengan perilaku default.

Pencocokan versi

Pengaturan versionMatchStrategy menentukan cara runtime mencocokkan versi orkestrasi ketika memuat fungsi orkestrator. Ini mengendalikan instans orkestrasi mana saja yang dapat diproses oleh pekerja berdasarkan kompatibilitas versi.

Configuration

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>",
      "versionMatchStrategy": "CurrentOrOlder"
    }
  }
}

Strategi yang tersedia

  • None (tidak disarankan): Abaikan versi orkestrasi sepenuhnya. Semua pekerjaan yang diterima diproses terlepas dari versinya. Strategi ini secara efektif menonaktifkan pemeriksaan versi dan memungkinkan setiap pekerja memproses instans orkestrasi apa pun.

  • Strict: Hanya memproses tugas dari orkestrasi dengan versi yang sama persis dengan versi yang ditentukan oleh defaultVersion dalam parameter pekerja host.json. Strategi ini memberikan tingkat isolasi versi tertinggi tetapi memerlukan koordinasi penyebaran yang cermat untuk menghindari orkestrasi yang terisolasi. Konsekuensi ketidakcocokan versi dijelaskan di bagian Penanganan versi yang tidak cocok .

  • CurrentOrOlder (default): Memproses tugas dari orkestrasi yang versinya kurang dari atau sama dengan versi yang ditentukan oleh defaultVersion dalam worker host.json. Strategi ini memungkinkan kompatibilitas mundur, memungkinkan pekerja yang lebih baru untuk menangani orkestrasi yang dimulai oleh versi orkestrator yang lebih lama sambil mencegah pekerja yang lebih lama memproses orkestrasi yang lebih baru. Konsekuensi ketidakcocokan versi dijelaskan di bagian Penanganan versi yang tidak cocok .

Penanganan ketidakcocokan versi

Pengaturan versionFailureStrategy menentukan tindakan yang diambil ketika versi instans orkestrasi tidak cocok dengan versi saat ini defaultVersion.

Configuration:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>",
      "versionFailureStrategy": "Reject"
    }
  }
}

Strategi yang tersedia:

  • Reject (default): Jangan memproses orkestrasi. Instans orkestrasi tetap dalam statusnya saat ini dan dapat dicoba kembali nanti ketika pekerja yang kompatibel tersedia. Strategi ini adalah opsi paling aman karena mempertahankan status orkestrasi.

  • Fail: Gagalkan orkestrasi. Strategi ini segera mengakhiri instans orkestrasi dengan status kegagalan, yang mungkin sesuai dalam skenario di mana ketidakcocokan versi menunjukkan masalah penyebaran serius.

Memulai orkestrasi dan sub-orkestrasi baru dengan versi tertentu

Secara bawaan, semua instans orkestrasi baru dibuat dengan defaultVersion saat ini yang ditentukan seperti dalam konfigurasi host.json Anda. Namun, Anda mungkin memiliki skenario di mana Anda perlu membuat orkestrasi dengan versi tertentu, bahkan jika berbeda dari default saat ini.

Kapan menggunakan versi tertentu:

  • Migrasi bertahap: Anda ingin terus membuat orkestrasi dengan versi yang lebih lama bahkan setelah menyebarkan versi yang lebih baru.
  • Skenario pengujian: Anda perlu menguji perilaku versi tertentu dalam produksi.
  • Situasi pengembalian: Anda perlu untuk sementara waktu kembali membuat instans dengan versi sebelumnya.
  • Alur kerja spesifik versi: Proses bisnis yang berbeda memerlukan pengaturan alur kerja versi yang berbeda.

Anda dapat mengambil alih versi default dengan memberikan nilai versi tertentu saat membuat instans orkestrasi baru menggunakan API klien orkestrasi. Ini memungkinkan kontrol terperinci atas versi mana yang digunakan setiap instans orkestrasi baru.

[Function("HttpStart")]
public static async Task<HttpResponseData> HttpStart(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
    [DurableClient] DurableTaskClient client,
    FunctionContext executionContext)
{
    var options = new StartOrchestrationOptions
    {
        Version = "1.0"
    };
    
    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("ProcessOrderOrchestrator", orderId, options);

    // ...
}

Anda juga dapat memulai sub-orkestrasi dengan versi tertentu dari dalam fungsi orkestrator:

[Function("MainOrchestrator")]
public static async Task<string> RunMainOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var subOptions = new SubOrchestratorOptions
    {
        Version = "1.0"
    };
    
    var result = await context.CallSubOrchestratorAsync<string>("ProcessPaymentOrchestrator", orderId, subOptions);
    
    // ...
}

Menghapus jalur kode warisan

Seiring waktu, Anda mungkin ingin menghapus jalur kode warisan dari fungsi orkestrator Anda untuk menyederhanakan pemeliharaan dan mengurangi utang teknis. Namun, menghapus kode harus dilakukan dengan hati-hati untuk menghindari kerusakan instans orkestrasi yang ada.

Saat aman untuk menghapus kode warisan:

  • Semua instans orkestrasi yang menggunakan versi lama telah selesai (berhasil, gagal, atau telah dihentikan)
  • Tidak ada instans orkestrasi baru yang akan dibuat dengan versi lama
  • Anda telah memverifikasi melalui pemantauan atau kueri bahwa tidak ada instans yang berjalan dengan versi usang
  • Periode waktu yang memadai telah berlalu sejak versi lama terakhir disebarkan (mempertimbangkan persyaratan kelangsungan bisnis Anda)

Praktik terbaik untuk penghapusan:

  • Memantau instans yang berjalan secara aktif: Gunakan API manajemen Durable Functions untuk mengkueri instans menggunakan versi tertentu.
  • Atur kebijakan retensi: Tentukan berapa lama Anda ingin mempertahankan kompatibilitas mundur untuk setiap versi.
  • Hapus secara bertahap: Pertimbangkan untuk menghapus satu versi sekaligus daripada beberapa versi secara bersamaan.
  • Penghapusan dokumen: Pertahankan catatan yang jelas tentang kapan versi dihapus dan mengapa.

Warning

Menghapus jalur kode warisan saat instans orkestrasi masih menjalankan versi tersebut dapat menyebabkan kegagalan pemutaran ulang deterministik atau perilaku yang tidak terduga. Selalu verifikasi bahwa tidak ada instans yang menggunakan versi warisan sebelum menghapus kode.

Praktik terbaik

Manajemen versi

  • Gunakan penerapan versi multi-bagian: Mengadopsi skema penerapan versi yang konsisten seperti major.minor.patch.
  • Dokumentasikan perubahan mendasar: Jelaskan dengan jelas perubahan apa yang memerlukan versi baru.
  • Rencanakan siklus hidup versi: Tentukan kapan harus menghapus jalur kode warisan.

Organisasi kode

  • Logika versi terpisah: Gunakan metode percabangan yang jelas atau terpisah untuk versi yang berbeda.
  • Mempertahankan determinisme: Hindari memodifikasi logika versi yang ada setelah disebarkan. Jika perubahan benar-benar diperlukan (seperti perbaikan bug penting), pastikan mereka mempertahankan perilaku deterministik dan tidak mengubah urutan operasi, atau mengharapkan versi orkestrator yang lebih baru gagal saat memproses orkestrasi yang lebih lama.
  • Uji secara menyeluruh: Uji semua jalur versi, terutama selama transisi.

Pemantauan dan pengamatan

  • Informasi versi log: Sertakan versi dalam proses log Anda untuk debugging yang lebih mudah.
  • Memantau distribusi versi: Lacak versi mana yang berjalan secara aktif.
  • Siapkan pemberitahuan: Pantau masalah terkait versi apa pun.

Troubleshooting

Masalah umum

  • Masalah: Instans orkestrasi yang dibuat dengan versi 1.0 gagal setelah menyebarkan versi 2.0

    • Solusi: Pastikan jalur kode versi 1.0 di orkestrator Anda tetap sama persis. Setiap perubahan pada urutan eksekusi dapat memutus pemutaran ulang deterministik.
  • Masalah: Pekerja yang menjalankan versi orkestrator yang lebih lama tidak dapat menjalankan orkestrasi baru

    • Solusi: Ini adalah perilaku yang diharapkan. Runtime sengaja mencegah pekerja yang lebih lama menjalankan orkestrasi dengan versi yang lebih baru untuk menjaga keamanan. Pastikan semua pekerja diperbarui ke versi orkestrator terbaru dan pengaturan defaultVersion mereka di host.json diperbarui sesuai. Anda dapat mengubah perilaku ini jika diperlukan menggunakan opsi konfigurasi tingkat lanjut (lihat Penggunaan tingkat lanjut untuk detailnya).
  • Masalah: Informasi versi tidak tersedia di orkestrator (context.Version atau context.getVersion() bernilai null, terlepas dari pengaturan defaultVersion)

    • Solusi: Periksa bagian Prasyarat untuk memastikan lingkungan Anda memenuhi semua persyaratan untuk penerapan versi orkestrasi.
  • Masalah: Orchestrasi versi terbaru membuat kemajuan yang sangat lambat atau terhenti sepenuhnya

    • Solusi: Masalahnya dapat memiliki akar penyebab yang berbeda:
      1. Kurangnya pekerja baru: Pastikan bahwa jumlah pekerja yang cukup dengan versi yang sama atau lebih tinggi disebarkan dan aktif defaultVersion untuk menangani orkestrasi yang baru.
      2. Gangguan perutean orkestrasi dari pekerja yang lebih tua: Pekerja lama dapat mengganggu mekanisme perutean orkestrasi, sehingga lebih sulit bagi pekerja baru untuk mengambil orkestrasi untuk diproses. Ini dapat sangat terlihat saat menggunakan penyedia penyimpanan tertentu (Azure Storage atau MSSQL). Biasanya, platform Azure Functions memastikan bahwa pekerja lama dibuang segera setelah penyebaran, sehingga penundaan apa pun biasanya tidak signifikan. Namun, jika Anda menggunakan konfigurasi yang memungkinkan Anda mengontrol siklus hidup pekerja yang lebih lama, pastikan pekerja yang lebih lama akhirnya dimatikan. Atau, pertimbangkan untuk menggunakan Penjadwal Tugas Tahan Lama, karena menyediakan mekanisme perutean yang ditingkatkan yang kurang rentan terhadap masalah ini.

Langkah selanjutnya