Saya baru saja mulai mencoba node.js beberapa hari yang lalu. Saya menyadari bahwa Node diakhiri setiap kali saya memiliki pengecualian yang tidak tertangani dalam program saya. Ini berbeda dari kontainer server normal yang telah saya hadapi di mana hanya Worker Thread yang mati ketika terjadi pengecualian yang tidak tertangani dan kontainer tersebut masih dapat menerima permintaan tersebut. Ini menimbulkan beberapa pertanyaan:
- Apakah
process.on('uncaughtException')
satu-satunya cara efektif untuk mencegahnya? - Akankah
process.on('uncaughtException')
menangkap pengecualian yang tidak ditangani selama eksekusi proses asinkron juga? - Apakah ada modul yang sudah dibangun (seperti mengirim email atau menulis ke file) yang dapat saya manfaatkan dalam kasus pengecualian yang tidak tertangkap?
Saya akan menghargai setiap pointer / artikel yang akan menunjukkan kepada saya praktik terbaik umum untuk menangani pengecualian yang tidak tertangkap di node.js
try .. catch
, dan periksa ini juga dilakukan untuk semua lib AndasetTimeout
atausetInterval
atau sesuatu semacam itu terkubur di suatu tempat yang dalam yang tidak dapat ditangkap oleh kode Anda.Jawaban:
Pembaruan: Joyent sekarang memiliki panduan sendiri . Informasi berikut ini lebih merupakan ringkasan:
Kesalahan "melempar" dengan aman
Idealnya kami ingin menghindari kesalahan yang tidak tertangkap sebanyak mungkin, dengan demikian, alih-alih benar-benar melempar kesalahan, kami dapat dengan aman "membuang" kesalahan menggunakan salah satu metode berikut tergantung pada arsitektur kode kami:
Untuk kode sinkron, jika terjadi kesalahan, kembalikan kesalahan:
Untuk kode berbasis callback (mis. Asinkron), argumen pertama dari callback adalah
err
, jika kesalahan terjadierr
adalah kesalahan, jika kesalahan tidak terjadi makaerr
adalahnull
. Argumen lain mengikutierr
argumen:Untuk kode kejadian , di mana kesalahan dapat terjadi di mana saja, alih-alih melempar kesalahan, jalankan
error
acara sebagai gantinya :Kesalahan "menangkap" dengan aman
Namun terkadang, mungkin masih ada kode yang melempar kesalahan di suatu tempat yang dapat menyebabkan pengecualian tanpa tertangkap dan kemungkinan crash aplikasi kita jika kita tidak menangkapnya dengan aman. Bergantung pada arsitektur kode kami, kami dapat menggunakan salah satu metode berikut untuk menangkapnya:
Ketika kita tahu di mana kesalahan terjadi, kita bisa membungkus bagian itu dalam domain node.js
Jika kita tahu di mana kesalahan terjadi adalah kode sinkron, dan untuk alasan apa pun tidak dapat menggunakan domain (mungkin versi lama dari node), kita dapat menggunakan pernyataan try catch:
Namun, berhati-hatilah untuk tidak menggunakan
try...catch
kode asinkron, karena kesalahan yang dilemparkan secara asinkron tidak akan ditangkap:Jika Anda ingin bekerja
try..catch
bersama dengan kode asinkron, saat menjalankan Node 7.4 atau lebih tinggi Anda dapat menggunakanasync/await
secara native untuk menulis fungsi asinkron Anda.Hal lain yang harus diperhatikan
try...catch
adalah risiko membungkus penyelesaian panggilan balik Anda di dalamtry
pernyataan seperti:Gotcha ini sangat mudah dilakukan karena kode Anda menjadi lebih kompleks. Dengan demikian, yang terbaik adalah menggunakan domain atau mengembalikan kesalahan untuk menghindari (1) pengecualian tanpa kode kodrat dalam sinkronisasi (2) mencoba menangkap pelaksanaan yang tidak Anda inginkan. Dalam bahasa yang memungkinkan untuk melakukan threading dengan benar alih-alih gaya mesin-peristiwa JavaScript yang tidak sinkron, ini kurang menjadi masalah.
Akhirnya, dalam kasus di mana kesalahan yang tidak tertangkap terjadi di tempat yang tidak terbungkus dalam domain atau pernyataan coba tangkap, kita dapat membuat aplikasi kita tidak macet dengan menggunakan
uncaughtException
pendengar (namun melakukan hal itu dapat menempatkan aplikasi dalam keadaan yang tidak diketahui ):sumber
try catch
? Karena saya ingin mendukung itu dengan bukti. Juga perbaiki contoh sinkronisasi.Berikut ini adalah ringkasan dan kurasi dari berbagai sumber tentang topik ini termasuk contoh kode dan kutipan dari posting blog yang dipilih. Daftar lengkap praktik terbaik dapat ditemukan di sini
Praktik terbaik penanganan kesalahan Node.JS
Nomor 1: Gunakan janji untuk penanganan kesalahan async
TL; DR: Menangani kesalahan async dalam gaya panggilan balik mungkin merupakan cara tercepat menuju neraka (alias piramida malapetaka). Hadiah terbaik yang dapat Anda berikan kepada kode Anda adalah menggunakan perpustakaan janji yang memiliki reputasi baik yang menyediakan banyak sintaksis kode yang ringkas dan akrab seperti try-catch
Sebaliknya: gaya panggilan balik Node.JS, fungsi (err, response), adalah cara yang menjanjikan untuk kode yang tidak dapat dipelihara karena campuran penanganan kesalahan dengan kode kasual, pola pengkodean sarang yang berlebihan dan canggung
Contoh kode - bagus
contoh kode anti pola - penanganan kesalahan gaya panggilan balik
Kutipan blog: "Kami memiliki masalah dengan janji" (Dari blog pouchdb, peringkat 11 untuk kata kunci "Node Promises")
Nomor2: Gunakan hanya objek Galat bawaan
TL; DR: Cukup umum untuk melihat kode yang melempar kesalahan sebagai string atau sebagai tipe khusus - ini mempersulit logika penanganan kesalahan dan interoperabilitas antar modul. Apakah Anda menolak janji, melempar pengecualian atau memancarkan kesalahan - menggunakan objek Galat bawaan Node.JS meningkatkan keseragaman dan mencegah hilangnya informasi kesalahan
Kalau tidak: Ketika menjalankan beberapa modul, menjadi tidak pasti jenis kesalahan apa yang akan kembali - membuatnya lebih sulit untuk alasan tentang pengecualian yang akan datang dan menanganinya. Bahkan layak, menggunakan tipe khusus untuk menggambarkan kesalahan dapat menyebabkan hilangnya informasi kesalahan kritis seperti jejak tumpukan!
Contoh kode - melakukannya dengan benar
contoh kode anti pola
Kutipan blog: "Sebuah string bukan kesalahan" (Dari blog renungkan, peringkat 6 untuk kata kunci "objek kesalahan Node.JS")
Nomor 3: Bedakan kesalahan operasional vs programmer
TL; DR: Kesalahan operasi (mis. API menerima input yang tidak valid) merujuk pada kasus yang diketahui di mana dampak kesalahan dipahami sepenuhnya dan dapat ditangani dengan bijaksana. Di sisi lain, kesalahan pemrogram (misalnya mencoba membaca variabel yang tidak terdefinisi) mengacu pada kegagalan kode yang tidak diketahui yang mengharuskan untuk me-restart aplikasi dengan anggun
Jika tidak: Anda selalu dapat memulai ulang aplikasi ketika kesalahan muncul, tetapi mengapa membiarkan ~ 5000 pengguna online down karena kesalahan kecil dan yang diperkirakan (kesalahan operasional)? sebaliknya juga tidak ideal - menjaga aplikasi tetap aktif ketika masalah yang tidak diketahui (kesalahan pemrogram) terjadi dapat menyebabkan perilaku yang tidak terduga. Membedakan keduanya memungkinkan bertindak bijaksana dan menerapkan pendekatan yang seimbang berdasarkan konteks yang diberikan
Contoh kode - melakukannya dengan benar
contoh kode - menandai kesalahan sebagai operasional (tepercaya)
Kutipan Blog : "Kalau tidak, Anda berisiko negara" (Dari blog debugable, peringkat 3 untuk kata kunci "Node.JS pengecualian tanpa tertangkap")
Nomor 4: Menangani kesalahan secara terpusat, melalui tetapi tidak di dalam middleware
TL; DR: Logika penanganan kesalahan seperti surat ke admin dan pencatatan harus dienkapsulasi dalam objek khusus dan terpusat yang dipanggil oleh semua titik akhir (mis. Middleware, pekerjaan cron, pengujian unit) ketika ada kesalahan.
Kalau tidak: Tidak menangani kesalahan dalam satu tempat akan menyebabkan duplikasi kode dan mungkin kesalahan yang ditangani dengan tidak tepat
Contoh kode - aliran kesalahan yang khas
Kutipan blog: "Kadang-kadang level yang lebih rendah tidak bisa melakukan apa pun kecuali menyebarkan kesalahan ke penelepon mereka" (Dari blog Joyent, peringkat 1 untuk kata kunci "Node.JS error handling")
Nomor5: Kesalahan dokumen API menggunakan Swagger
TL; DR: Biarkan penelepon API Anda tahu kesalahan mana yang mungkin terjadi sehingga mereka dapat menangani ini dengan serius tanpa menabrak. Ini biasanya dilakukan dengan kerangka dokumentasi REST API seperti Swagger
Kalau tidak: Klien API mungkin memutuskan untuk mogok dan memulai kembali hanya karena ia menerima kembali kesalahan yang tidak dapat ia pahami. Catatan: penelepon API Anda mungkin Anda (sangat tipikal dalam lingkungan layanan mikro)
Kutipan blog: "Anda harus memberi tahu penelepon Anda kesalahan apa yang bisa terjadi" (Dari blog Joyent, peringkat 1 untuk kata kunci “Node.JS logging”)
Nomor 6: Tutup proses dengan anggun ketika orang asing datang ke kota
TL; DR: Ketika terjadi kesalahan yang tidak diketahui (kesalahan pengembang, lihat praktik terbaik nomor 3) - ada ketidakpastian tentang kesehatan aplikasi. Praktik umum menyarankan memulai kembali proses dengan hati-hati menggunakan alat 'restarter' seperti Forever dan PM2
Jika tidak: Ketika pengecualian yang tidak dikenal ditangkap, beberapa objek mungkin berada dalam kondisi rusak (mis. Emitor peristiwa yang digunakan secara global dan tidak memecat peristiwa lagi karena beberapa kegagalan internal) dan semua permintaan di masa depan mungkin gagal atau berperilaku gila-gilaan
Contoh kode - memutuskan apakah akan mogok
Kutipan blog: "Ada tiga aliran pemikiran tentang penanganan kesalahan" (Dari blog jsrecipes)
Nomor7: Gunakan logger dewasa untuk meningkatkan visibilitas kesalahan
TL; DR: Satu set alat logging yang matang seperti Winston, Bunyan atau Log4J, akan mempercepat penemuan dan pemahaman kesalahan. Jadi, lupakan tentang console.log.
Kalau tidak: Melacak melalui console.logs atau secara manual melalui file teks yang berantakan tanpa alat kueri atau penampil log yang baik mungkin membuat Anda sibuk di tempat kerja hingga larut
Contoh kode - Winston logger sedang beraksi
Kutipan blog: "Mari mengidentifikasi beberapa persyaratan (untuk logger):" (Dari blog blog kuat)
Nomor 8: Temukan kesalahan dan waktu henti menggunakan produk APM
TL; DR: Pemantauan dan produk kinerja (alias APM) secara proaktif mengukur basis kode atau API Anda sehingga mereka dapat secara otomatis menyoroti kesalahan, kerusakan, dan bagian lambat yang Anda lewatkan
Jika tidak: Anda mungkin berusaha keras untuk mengukur kinerja dan waktu henti API, mungkin Anda tidak akan pernah menyadari bagian kode mana yang paling lambat dalam skenario dunia nyata dan bagaimana hal ini mempengaruhi UX
Kutipan blog: "Segmen produk APM" (Dari blog Yoni Goldberg)
Versi di atas adalah versi singkat - lihat di sini lebih banyak praktik dan contoh terbaik
sumber
Anda dapat menangkap pengecualian tanpa tertangkap, tetapi penggunaannya terbatas. Lihat http://debuggable.com/posts/node-js-dealing-with-uncrupt-exeptionions:4c933d54-1428-443c-928d-4e1ecbdd56cb
monit
,forever
atauupstart
dapat digunakan untuk memulai kembali proses simpul saat macet. Shutdown yang anggun adalah yang terbaik yang dapat Anda harapkan (mis. Menyimpan semua data dalam memori dalam handler pengecualian yang tidak tertangkap).sumber
Error
membuat nilai kembali polimorfik yang mengacaukan semantik fungsi yang tidak perlu. Selanjutnya, diving oleh 0 sudah ditangani JavaScript dengan memberikanInfinity
,-Infinity
atauNaN
, nilai-nilai manatypeof === 'number'
. Mereka dapat diperiksa dengan!isFinite(value)
. Secara umum saya akan merekomendasikan untuk tidak pernah mengembalikan Kesalahan dari suatu fungsi. Lebih baik dalam hal keterbacaan kode dan pemeliharaan untuk melempar atau mengembalikan nilai non-polimorfik khusus dengan semantik yang konsisten.domain nodejs adalah cara paling terbaru untuk menangani kesalahan dalam nodejs. Domain dapat menangkap kesalahan / peristiwa lainnya serta benda yang dilempar secara tradisional. Domain juga menyediakan fungsionalitas untuk menangani panggilan balik dengan kesalahan yang diteruskan sebagai argumen pertama melalui metode intersepsi.
Seperti halnya penanganan kesalahan gaya coba / tangkapan biasa, biasanya yang terbaik adalah membuang kesalahan saat terjadi, dan memblokir area di mana Anda ingin mengisolasi kesalahan agar tidak mempengaruhi sisa kode. Cara untuk "memblokir" area ini adalah dengan memanggil domain.run dengan fungsi sebagai blok kode yang terisolasi.
Dalam kode sinkron, hal di atas sudah cukup - ketika terjadi kesalahan, Anda dapat membiarkannya dilemparkan, atau Anda menangkapnya dan menanganinya, mengembalikan data apa pun yang perlu Anda kembalikan.
Ketika kesalahan terjadi dalam callback asinkron, Anda juga harus dapat sepenuhnya menangani rollback data (keadaan bersama, data eksternal seperti database, dll). ATAU Anda harus menetapkan sesuatu untuk menunjukkan bahwa pengecualian telah terjadi - di mana pun Anda peduli tentang bendera itu, Anda harus menunggu sampai panggilan balik selesai.
Beberapa dari kode di atas jelek, tetapi Anda dapat membuat pola sendiri agar lebih cantik, misalnya:
UPDATE (2013-09):
Di atas, saya menggunakan masa depan yang menyiratkan serat semantik , yang memungkinkan Anda untuk menunggu di masa depan sejalan. Ini sebenarnya memungkinkan Anda untuk menggunakan blok try-catch tradisional untuk semuanya - yang saya temukan sebagai cara terbaik untuk melakukannya. Namun, Anda tidak dapat selalu melakukan ini (yaitu di browser) ...
Ada juga futures yang tidak memerlukan serat semantik (yang kemudian berfungsi dengan normal, JavaScript JavaScript). Ini bisa disebut berjangka, janji, atau ditangguhkan (saya akan merujuk ke berjangka mulai dari sini). Pustaka futures JavaScript-lama-polos memungkinkan kesalahan disebarkan di antara futures. Hanya beberapa perpustakaan ini yang memungkinkan masa depan yang dilempar untuk ditangani dengan benar, jadi waspadalah.
Sebuah contoh:
Ini meniru try-catch normal, meskipun potongannya tidak sinkron. Itu akan mencetak:
Perhatikan bahwa itu tidak mencetak '3' karena pengecualian dilemparkan yang mengganggu aliran itu.
Lihatlah janji-janji bluebird:
Perhatikan bahwa saya belum menemukan banyak perpustakaan lain selain ini yang benar-benar menangani pengecualian. jQuery ditangguhkan, misalnya, jangan - penangan "gagal" tidak akan pernah mendapatkan pengecualian dilemparkan penangan 'maka', yang menurut saya adalah pemecah kesepakatan.
sumber
Saya menulis tentang ini baru-baru ini di http://snmaynard.com/2012/12/21/node-error-handling/ . Fitur baru node dalam versi 0.8 adalah domain dan memungkinkan Anda untuk menggabungkan semua bentuk penanganan kesalahan ke dalam satu formulir pengelolaan yang lebih mudah. Anda dapat membaca tentang mereka di posting saya.
Anda juga dapat menggunakan sesuatu seperti Bugsnag untuk melacak pengecualian Anda yang tidak tertangkap dan diberitahukan melalui email, chatroom atau membuat tiket yang dibuat untuk pengecualian yang tidak tertangkap (Saya adalah salah satu pendiri Bugsnag).
sumber
Saya hanya ingin menambahkan bahwa perpustakaan Step.js membantu Anda menangani pengecualian dengan selalu meneruskannya ke fungsi langkah berikutnya. Oleh karena itu, Anda dapat memiliki sebagai langkah terakhir fungsi yang memeriksa kesalahan pada langkah-langkah sebelumnya. Pendekatan ini dapat sangat menyederhanakan penanganan kesalahan Anda.
Di bawah ini adalah kutipan dari halaman github:
Selanjutnya, Anda dapat menggunakan Langkah untuk mengontrol eksekusi skrip untuk memiliki bagian pembersihan sebagai langkah terakhir. Misalnya jika Anda ingin menulis skrip build di Node dan melaporkan berapa lama waktu yang dibutuhkan untuk menulis, langkah terakhir dapat melakukannya (daripada mencoba menggali callback terakhir).
sumber
Salah satu contoh di mana menggunakan try-catch mungkin tepat adalah ketika menggunakan forEach loop. Ini sinkron tetapi pada saat yang sama Anda tidak bisa hanya menggunakan pernyataan kembali dalam lingkup dalam. Sebagai gantinya pendekatan coba dan tangkap dapat digunakan untuk mengembalikan objek Galat dalam cakupan yang sesuai. Mempertimbangkan:
Ini adalah kombinasi dari pendekatan yang dijelaskan oleh @balupton di atas.
sumber
Setelah membaca posting ini beberapa waktu lalu saya bertanya-tanya apakah aman menggunakan domain untuk penanganan pengecualian pada tingkat api / fungsi. Saya ingin menggunakannya untuk menyederhanakan penanganan kode pengecualian di setiap fungsi async yang saya tulis. Kekhawatiran saya adalah bahwa menggunakan domain baru untuk setiap fungsi akan menghasilkan overhead yang signifikan. Pekerjaan rumah saya tampaknya menunjukkan bahwa ada overhead minimal dan bahwa kinerja sebenarnya lebih baik dengan domain daripada dengan coba tangkap dalam beberapa situasi.
http://www.lighthouselogic.com/#/using-a-new-domain-for-each-async-function-in-node/
sumber
Menangkap kesalahan telah dibahas dengan sangat baik di sini, tetapi perlu diingat untuk mencatat kesalahan di suatu tempat sehingga Anda dapat melihatnya dan memperbaiki masalahnya.
Bunyan adalah kerangka kerja pencatatan populer untuk NodeJS - ini mendukung penulisan ke banyak tempat keluaran berbeda yang membuatnya berguna untuk debugging lokal, selama Anda menghindari konsol.log. Di penangan kesalahan domain Anda, Anda bisa meludahkan kesalahan ke file log.
Ini bisa memakan waktu lama jika Anda memiliki banyak kesalahan dan / atau server untuk memeriksa, jadi mungkin ada baiknya melihat ke alat seperti Raygun (penafian, saya bekerja di Raygun) untuk mengelompokkan kesalahan bersama - atau menggunakannya bersama-sama. Jika Anda memutuskan untuk menggunakan Raygun sebagai alat, itu juga cukup mudah untuk diatur
Dilintasi dengan menggunakan alat seperti PM2 atau selamanya, aplikasi Anda seharusnya bisa macet, keluar apa yang terjadi dan reboot tanpa masalah besar.
sumber
Jika Anda ingin menggunakan Layanan di Ubuntu (Pemula): Node sebagai layanan di Ubuntu 11,04 dengan pemula, monit, dan forever.js
sumber