Mencoba lagi fungsi asinkron

Dokumen ini menjelaskan cara meminta fungsi background asinkron (non-HTTPS) yang akan dicoba ulang saat terjadi kegagalan.

Semantik percobaan ulang

Cloud Functions menjamin setidaknya sekali eksekusi fungsi berbasis peristiwa untuk setiap peristiwa yang dikeluarkan oleh sumber peristiwa. Namun, secara default, jika pemanggilan fungsi berhenti dengan pesan error, fungsi tersebut tidak akan dipanggil lagi, dan peristiwa akan dibatalkan. Saat Anda mengaktifkan percobaan ulang pada fungsi berbasis peristiwa, Cloud Functions akan mencoba kembali pemanggilan fungsi yang gagal hingga berhasil diselesaikan, atau periode percobaan ulang berakhir. Untuk fungsi generasi ke-2, periode percobaan ulang akan berakhir setelah 24 jam. Untuk fungsi generasi ke-1, periode percobaan ulang akan berakhir setelah 7 hari. Fungsi berbasis peristiwa yang baru dibuat akan mencoba ulang menggunakan strategi backoff eksponensial, dengan backoff minimum 10 detik dan backoff maksimum 600 detik, atau sepuluh menit. Kebijakan ini diterapkan ke fungsi baru saat pertama kali di-deploy. Kebijakan ini tidak berlaku surut untuk fungsi yang sudah ada dan pertama kali di-deploy sebelum perubahan yang dijelaskan dalam catatan rilis ini mulai diterapkan, meskipun Anda men-deploy ulang fungsi tersebut.

Jika percobaan ulang tidak diaktifkan untuk suatu fungsi, yang merupakan setelan default, fungsi tersebut akan selalu melaporkan keberhasilan eksekusinya, dan kode respons 200 OK mungkin muncul dalam log-nya. Ini bisa terjadi meskipun fungsi mengalami error. Untuk medapatkan informasi yang jelas saat fungsi Anda mengalami error, pastikan untuk melaporkan error dengan tepat.

Alasan fungsi berbasis peristiwa gagal diselesaikan

Terkadang, fungsi keluar sebelum waktunya karena terjadi error internal, dan secara default fungsi tersebut akan atau tidak akan dicoba ulang secara otomatis.

Biasanya, fungsi berbasis peristiwa dapat gagal diselesaikan karena terjadi error pada kode fungsi itu sendiri. Beberapa penyebabnya adalah sebagai berikut:

  • Fungsi berisi bug dan runtime menampilkan pengecualian.
  • Fungsi tidak dapat menjangkau endpoint layanan, atau waktu habis saat mencoba menjangkau endpoint.
  • Fungsi sengaja menampilkan pengecualian (misalnya, saat parameter menggagalkan validasi).
  • Jika fungsi yang ditulis dalam Node.js menampilkan promise yang ditolak atau meneruskan nilai bukan null ke callback.

Dalam kasus di atas, secara default fungsi akan berhenti dijalankan dan peristiwa itu akan dihapus. Jika ingin mencoba ulang fungsi ini ketika terjadi error, Anda dapat mengubah kebijakan percobaan ulang default dengan menyetel properti "coba ulang jika gagal". Dengan mengambil langkah ini, peristiwa akan dicoba ulang berkali-kali hingga beberapa hari sampai fungsi tersebut berhasil diselesaikan.

Mengaktifkan dan menonaktifkan percobaan ulang

Menggunakan GCP Console

Anda dapat mengaktifkan atau menonaktifkan percobaan ulang di GCP Console sebagai berikut:

  1. Buka halaman Ringkasan Cloud Functions di Cloud Platform Console.

  2. Klik Buat fungsi. Atau, klik fungsi yang ada untuk membuka halaman detailnya dan klik Edit.

  3. Lengkapi kolom wajib isi untuk fungsi Anda.

  4. Pastikan kolom Pemicu disetel ke jenis pemicu berdasarkan peristiwa, seperti Cloud Pub/Sub atau Cloud Storage.

  5. Perluas setelan lanjutan dengan mengklik Lainnya.

  6. Centang atau hapus centang pada kotak dengan label Coba lagi jika gagal.

Dalam kode fungsi

Dengan Cloud Functions for Firebase, Anda dapat mengaktifkan percobaan ulang dalam kode untuk suatu fungsi. Untuk melakukannya pada fungsi latar belakang seperti functions.foo.onBar(myHandler);, gunakan runWith dan konfigurasikan kebijakan kegagalan:

functions.runWith({failurePolicy: true}).foo.onBar(myHandler);

Menyetel true seperti yang ditampilkan akan mengonfigurasi fungsi untuk mencoba lagi jika gagal.

Praktik terbaik

Bagian ini menjelaskan praktik terbaik untuk menggunakan percobaan ulang.

Menggunakan percobaan ulang untuk menangani error sementara

Karena fungsi terus dicoba ulang hingga berhasil dijalankan, error permanen, seperti bug, harus dihilangkan dari kode Anda melalui pengujian menyeluruh sebelum percobaan ulang diaktifkan. Percobaan ulang paling baik digunakan untuk menangani kegagalan yang terputus-putus/sementara yang sangat mungkin akan teratasi melalui percobaan ulang, seperti endpoint layanan yang tidak stabil atau waktu tunggu habis.

Menetapkan kondisi akhir agar percobaan ulang tidak terjebak dalam loop tanpa henti

Salah satu praktik terbaik adalah melindungi fungsi Anda dari loop terus-menerus saat menggunakan percobaan ulang. Anda dapat melakukannya dengan menyertakan kondisi akhir yang ditetapkan dengan baik, sebelum fungsi mulai diproses. Ingat bahwa teknik ini hanya berfungsi jika fungsi Anda berhasil dimulai dan dapat mengevaluasi kondisi akhir.

Pendekatan yang sederhana tetapi efektif adalah dengan menghapus peristiwa yang memiliki stempel waktu lebih lama dari rentang tertentu. Langkah ini dapat menghindari eksekusi berlebihan saat kegagalan terus-menerus terjadi atau berlangsung lebih lama daripada perkiraan.

Misalnya, cuplikan kode ini menghapus semua peristiwa yang lebih lama dari 10 detik:

const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
  console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
  callback();
  return;
}

Menggunakan catch dengan Promise

Jika fungsi Anda mengaktifkan percobaan ulang, error yang tidak ditangani akan memicu percobaan ulang. Pastikan kode Anda menangkap error yang seharusnya tidak menyebabkan percobaan ulang.

Berikut adalah contoh tindakan yang sebaiknya Anda lakukan:

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

Membuat fungsi berbasis peristiwa yang dapat dicoba ulang jadi bersifat idempoten

Fungsi berdasarkan peristiwa yang dapat dicoba lagi harus bersifat idempoten. Berikut adalah beberapa panduan umum untuk membuat fungsi bersifat idempoten:

  • Banyak API eksternal (seperti Stripe) yang dapat Anda gunakan untuk menyuplai kunci idempotensi sebagai parameter. Jika menggunakan API seperti itu, Anda harus menggunakan ID peristiwa sebagai kunci idempotensi.
  • Idempotensi berfungsi dengan baik pada pengiriman "setidaknya sekali" karena memberikan keamanan untuk mencoba ulang. Jadi, salah satu praktik terbaik yang umum untuk menulis kode tepercaya adalah dengan menggabungkan idempotensi dengan percobaan ulang.
  • Pastikan kode Anda idempoten secara internal. Contoh:
    • Pastikan mutasi bisa terjadi lebih dari sekali tanpa mengubah hasilnya.
    • Jalankan kueri pada status database dalam transaksi sebelum memutasikan status tersebut.
    • Pastikan semua efek samping bersifat idempoten.
  • Lakukan pemeriksaan transaksi di luar fungsi, terlepas dari kode. Sebagai contoh, pertahankan status di suatu tempat yang mencatat bahwa ID peristiwa tertentu telah diproses.
  • Tangani panggilan fungsi duplikat yang tidak umum. Misalnya, jalankan proses pembersihan terpisah yang akan melakukan pembersihan setelah panggilan fungsi duplikat.

Mengonfigurasi kebijakan percobaan ulang

Bergantung pada kebutuhan Cloud Function Anda, kebijakan percobaan ulang juga dapat dikonfigurasi secara langsung. Dengan begitu, Anda akan dapat menyiapkan kombinasi berikut:

  • Mempersingkat periode percobaan ulang dari 7 hari menjadi hanya 10 menit.
  • Mengubah waktu backoff minimum dan maksimum untuk strategi percobaan ulang backoff eksponensial.
  • Mengubah strategi percobaan ulang untuk mencoba ulang dengan seketika.
  • Mengonfigurasi topik yang dihentikan pengirimannya.
  • Menetapkan jumlah upaya pengiriman maksimum dan minimum.

Untuk mengonfigurasi kebijakan percobaan ulang:

  1. Tulis fungsi HTTP.
  2. Gunakan Pub/Sub API untuk membuat langganan Pub/Sub, dengan menentukan URL fungsi sebagai target.

Lihat dokumentasi Pub/Sub mengenai penanganan kegagalan untuk mengetahui informasi selengkapnya tentang cara mengonfigurasi Pub/Sub secara langsung.