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 menyediakan setidaknya sekali eksekusi fungsi berbasis peristiwa untuk setiap peristiwa yang dikeluarkan oleh sumber peristiwa. Secara default, jika pemanggilan fungsi dihentikan dengan error, fungsi tersebut tidak akan dipanggil lagi dan peristiwa akan dihapus. 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. Cloud Functions mencoba kembali fungsi berbasis peristiwa yang baru dibuat menggunakan strategi backoff eksponensial, dengan backoff yang meningkat antara 10 dan 600 detik. 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. Alasan terjadinya hal ini meliputi:

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

Dalam kasus ini, fungsi akan berhenti dijalankan secara default dan peristiwa itu akan dihapus. Untuk mencoba kembali fungsi ini saat terjadi error, Anda dapat mengubah kebijakan coba lagi default dengan menyetel properti "coba lagi jika gagal". Hal ini menyebabkan peristiwa tersebut dicoba ulang berulang kali hingga fungsi berhasil diselesaikan atau waktu tunggu percobaan ulang berakhir.

Mengaktifkan atau menonaktifkan percobaan ulang

Mengonfigurasi percobaan ulang dari konsol

Jika Anda membuat fungsi baru:

  1. Dari layar Create Function, di bagian Trigger, pilih jenis peristiwa yang akan bertindak sebagai pemicu untuk fungsi Anda.
  2. Centang kotak Retry on failure untuk mengaktifkan percobaan ulang.

Jika Anda mengupdate fungsi yang sudah ada:

  1. Dari halaman Cloud Functions Overview, klik nama fungsi yang ingin Anda update untuk membuka layar Function details, lalu pilih Edit dari panel menu untuk menampilkan panel Trigger.
  2. Centang atau hapus centang pada kotak Retry on failure untuk mengaktifkan atau menonaktifkan percobaan ulang.

Mengonfigurasi percobaan ulang dari 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 atau 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 fungsi 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.