Bagaimana cara mencegah agar node.js tidak mogok? coba-tangkap tidak bekerja

157

Dari pengalaman saya, sebuah server php akan melemparkan pengecualian ke log atau ke server, tetapi node.js hanya crash. Mengitari kode saya dengan try-catch tidak berfungsi karena semuanya dilakukan secara tidak sinkron. Saya ingin tahu apa yang dilakukan orang lain di server produksi mereka.

TiansHUo
sumber

Jawaban:

132

Jawaban lain benar-benar gila karena Anda dapat membaca di dokumen Node sendiri di http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception

Jika seseorang menggunakan jawaban lain, baca Node Docs:

Perhatikan bahwa uncaughtExceptionini adalah mekanisme yang sangat kasar untuk penanganan pengecualian dan dapat dihapus di masa depan

PM2

Pertama-tama, saya sangat merekomendasikan PM2untuk menginstal Node.js. PM2 sangat hebat dalam menangani crash dan memonitor aplikasi Node serta load balancing. PM2 segera memulai aplikasi Node setiap kali crash, berhenti karena alasan apa pun atau bahkan ketika server restart. Jadi, jika suatu hari bahkan setelah mengelola kode kami, aplikasi macet, PM2 dapat segera memulai kembali. Untuk info lebih lanjut, Menginstal dan Menjalankan PM2

Sekarang kembali ke solusi kami untuk mencegah aplikasi itu sendiri crash.

Jadi setelah melewati akhirnya saya menemukan apa yang disarankan oleh Node document:

Jangan gunakan uncaughtException, gunakan domainsdengan clustersebagai gantinya. Jika Anda menggunakannya uncaughtException, mulai ulang aplikasi Anda setelah setiap pengecualian yang tidak tertangani!

DOMAIN dengan Cluster

Apa yang sebenarnya kita lakukan adalah mengirim respons kesalahan ke permintaan yang memicu kesalahan, sambil membiarkan yang lain selesai dalam waktu normal mereka, dan berhenti mendengarkan permintaan baru pada pekerja itu.

Dengan cara ini, penggunaan domain berjalan seiring dengan modul gugus, karena proses master dapat memotong seorang pekerja baru ketika seorang pekerja menemukan kesalahan. Lihat kode di bawah ini untuk memahami apa yang saya maksud

Dengan menggunakan Domain, dan ketahanan memisahkan program kami menjadi beberapa proses pekerja menggunakan Cluster, kami dapat bereaksi lebih tepat, dan menangani kesalahan dengan keamanan yang jauh lebih besar.

var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;

if(cluster.isMaster) 
{
   cluster.fork();
   cluster.fork();

   cluster.on('disconnect', function(worker) 
   {
       console.error('disconnect!');
       cluster.fork();
   });
} 
else 
{
    var domain = require('domain');
    var server = require('http').createServer(function(req, res) 
    {
        var d = domain.create();
        d.on('error', function(er) 
        {
            //something unexpected occurred
            console.error('error', er.stack);
            try 
            {
               //make sure we close down within 30 seconds
               var killtimer = setTimeout(function() 
               {
                   process.exit(1);
               }, 30000);
               // But don't keep the process open just for that!
               killtimer.unref();
               //stop taking new requests.
               server.close();
               //Let the master know we're dead.  This will trigger a
               //'disconnect' in the cluster master, and then it will fork
               //a new worker.
               cluster.worker.disconnect();

               //send an error to the request that triggered the problem
               res.statusCode = 500;
               res.setHeader('content-type', 'text/plain');
               res.end('Oops, there was a problem!\n');
           } 
           catch (er2) 
           {
              //oh well, not much we can do at this point.
              console.error('Error sending 500!', er2.stack);
           }
       });
    //Because req and res were created before this domain existed,
    //we need to explicitly add them.
    d.add(req);
    d.add(res);
    //Now run the handler function in the domain.
    d.run(function() 
    {
        //You'd put your fancy application logic here.
        handleRequest(req, res);
    });
  });
  server.listen(PORT);
} 

Meskipun Domainsedang menunggu penghentian dan akan dihapus sebagai pengganti baru datang seperti yang dinyatakan dalam Dokumentasi Node

Modul ini sedang menunggu penghentian. Setelah API pengganti diselesaikan, modul ini akan sepenuhnya tidak digunakan lagi. Pengguna yang benar-benar harus memiliki fungsionalitas yang disediakan domain dapat mengandalkannya untuk saat ini tetapi harus berharap harus bermigrasi ke solusi yang berbeda di masa mendatang.

Tetapi sampai penggantian baru tidak diperkenalkan, Domain dengan Cluster adalah satu-satunya solusi yang bagus seperti yang disarankan oleh Node Documentation.

Untuk memahami Domaindan Clustermembaca secara mendalam

https://nodejs.org/api/domain.html#domain_domain (Stability: 0 - Deprecated)

https://nodejs.org/api/cluster.html

Terima kasih kepada @Stanley Luo karena telah membagikan kepada kami penjelasan mendalam yang luar biasa tentang Cluster dan Domains ini

Cluster & Domains

Airy
sumber
9
Sebuah kata peringatan, Domain sedang dalam penghentian: tautan . Metode yang disarankan, dari docs Node, adalah untuk penggunaan klaster: Link .
Paul
4
restart your application after every unhandled exception!Dalam kasus 2000 pengguna menggunakan server web node untuk streaming video dan 1 pengguna mendapat pengecualian maka memulai ulang tidak akan mengganggu semua pengguna lain?
Vikas Bansal
2
@VikasBansal Ya itu pasti akan mengganggu semua pengguna dan itu sebabnya itu buruk untuk digunakan uncaughtExceptiondan digunakan Domaindengan Clusterdemikian, jika satu pengguna menghadapi pengecualian maka hanya utasnya yang dihapus dari cluster dan dibuat yang baru untuknya. Dan Anda tidak perlu me-restart server Node Anda juga. Sementara di sisi lain jika Anda menggunakan uncaughtExceptionAnda harus me-restart server Anda setiap kali ada pengguna Anda menghadapi masalah. Jadi, gunakan Domain dengan Cluster.
Airy
3
apa yang harus kita lakukan ketika domainsudah sepenuhnya ditinggalkan dan dihapus?
Jas
3
Menemukan tutorial ini untuk mereka yang tidak mengerti konsep clusterdan workers: sitepoint.com/...
Stanley Luo
81

Saya menempatkan kode ini tepat di bawah pernyataan dan deklarasi global yang saya perlukan:

process.on('uncaughtException', function (err) {
  console.error(err);
  console.log("Node NOT Exiting...");
});

bekerja untukku. satu-satunya hal yang saya tidak suka tentang itu adalah saya tidak mendapatkan info sebanyak yang saya akan jika saya membiarkan hal itu crash.

hvgotcodes
sumber
45
Peringatan: metode ini berfungsi baik, TAPI ingat bahwa SEMUA respons HTTP harus diakhiri dengan benar. Itu berarti bahwa jika pengecualian tanpa tertangkap terjadi saat Anda menangani permintaan HTTP, Anda masih harus memanggil end () pada Objek http.ServerResponse. Namun Anda menerapkan ini terserah Anda. Jika Anda tidak melakukan ini, permintaan akan hang sampai browser menyerah. Jika Anda memiliki cukup permintaan ini, server dapat kehabisan memori.
BMiner
3
@BMiner, dapatkah Anda memberikan implementasi yang lebih baik? Saya perhatikan masalah ini (permintaan menggantung) jadi ini benar-benar tidak lebih baik daripada hanya me-restart server menggunakan foreveratau sesuatu.
pixelfreak
6
Ini membutuhkan penjelasan mendalam. Saya tahu ini menyebalkan, tetapi setiap kali terjadi pengecualian yang tidak tertangkap, server Anda harus melakukan reboot ASAP. Sungguh, tujuan dari acara 'uncaughtException' adalah untuk menggunakannya sebagai kesempatan untuk mengirim email peringatan, dan kemudian gunakan process.exit (1); untuk mematikan server. Anda dapat menggunakan selamanya atau sesuatu seperti itu untuk me-restart server. Setiap permintaan HTTP yang tertunda akan habis dan gagal. Pengguna Anda akan marah pada Anda. Tapi, itu solusi terbaik. Mengapa kamu bertanya? Checkout stackoverflow.com/questions/8114977/…
BMiner
3
Untuk mendapatkan informasi lebih lanjut dari kesalahan yang tidak tertangkap, gunakan: console.trace (err.stack);
Jesse Dunlap
2
PERINGATAN: Dokumentasi untuk node mengatakan, tanpa syarat yang pasti, bahwa Anda tidak boleh melakukan ini karena ini berbahaya: nodejs.org/api/process.html#process_event_uncaughtexception
Jeremy Logan
28

Seperti disebutkan di sini, Anda akan menemukan error.stackmenyediakan pesan kesalahan yang lebih lengkap seperti nomor baris yang menyebabkan kesalahan:

process.on('uncaughtException', function (error) {
   console.log(error.stack);
});
Sean Bannister
sumber
12

Mencoba supervisor

npm install supervisor
supervisor app.js

Atau Anda dapat menginstal forever .

Semua ini akan dilakukan adalah memulihkan server Anda ketika crash dengan me-restart itu.

forever dapat digunakan dalam kode untuk memulihkan proses apa pun yang macet secara anggun.

The foreverdocs memiliki informasi yang solid pada penanganan pemrograman keluar / error.

Raynos
sumber
9
Tentunya ini tidak bisa menjadi solusinya ... Pada saat server sedang down, itu tidak bisa menanggapi permintaan masuk baru. Pengecualian mungkin dilemparkan dari kode aplikasi - server perlu merespons dengan kesalahan 500, tidak hanya crash dan berharap itu dimulai kembali.
Ant Kutschera
20
Jadi sebagai seorang hacker, orang dapat mengetahui bahwa mereka perlu mengirim permintaan sederhana ke server dan melewatkan parameter permintaan - yang mengarah ke undef di javascript yang menyebabkan node.js mogok. Dengan saran Anda, saya dapat membunuh seluruh cluster Anda berulang kali. Jawabannya adalah membuat aplikasi gagal dengan anggun - yaitu menangani pengecualian yang tidak tertangkap dan tidak macet. bagaimana jika server menangani banyak sesi voip? itu tidak dapat diterima untuk crash dan burn dan untuk semua sesi yang ada untuk mati bersamanya. pengguna Anda akan segera pergi.
Ant Kutschera
5
@AntKutschera itu sebabnya pengecualian harus menjadi kasus luar biasa. Pengecualian hanya akan diaktifkan dalam situasi di mana Anda tidak dapat memulihkan dan di mana proses harus macet. Anda harus menggunakan cara lain untuk menangani kasus luar biasa ini . Tapi saya mengerti maksud Anda. Anda harus gagal dengan anggun jika memungkinkan. Namun ada kasus di mana melanjutkan dengan negara yang rusak akan membuat lebih banyak kerusakan.
Raynos
2
Ya, ada berbagai aliran pemikiran di sini. Cara saya mempelajarinya (Java daripada Javascript) ada expeksi yang dapat diterima yang seharusnya Anda harapkan, dikenal sebagai pengecualian bisnis, dan kemudian ada pengecualian runtime atau kesalahan, di mana Anda seharusnya tidak berharap untuk pulih, seperti kehabisan memori. Satu masalah dengan tidak gagal dengan anggun adalah bahwa beberapa perpustakaan yang saya tulis mungkin menyatakan bahwa ia melemparkan pengecualian dalam kasus sesuatu yang dapat dipulihkan, katakanlah di mana pengguna dapat memperbaiki input mereka. di aplikasi Anda, Anda tidak membaca dokumen saya dan hanya crash, di mana pengguna mungkin dapat pulih
Ant Kutschera
1
@AntKutschera Inilah sebabnya kami mencatat pengecualian. Anda harus menganalisis log produksi Anda untuk pengecualian umum, dan mencari tahu apakah dan bagaimana Anda bisa memulihkannya, daripada membiarkan server crash. Saya telah menggunakan metodologi itu dengan PHP, Ruby on Rails, dan Node. Terlepas dari apakah Anda keluar atau tidak dari suatu proses, setiap kali Anda memunculkan kesalahan 500, Anda merugikan pengguna. Ini bukan JavaScript atau praktik khusus Node.
Eric Elliott
7

Menggunakan try-catch dapat memecahkan kesalahan yang tidak tertangkap, tetapi dalam beberapa situasi yang kompleks, itu tidak akan melakukan pekerjaan dengan benar seperti menangkap fungsi async. Ingatlah bahwa di Node, panggilan fungsi async apa pun dapat berisi kemungkinan operasi mogok aplikasi.

Menggunakan uncaughtExceptionadalah solusi tetapi itu diakui sebagai tidak efisien dan kemungkinan akan dihapus di versi Node masa depan, jadi jangan mengandalkan itu.

Solusi ideal adalah menggunakan domain: http://nodejs.org/api/domain.html

Untuk memastikan aplikasi Anda aktif dan berjalan meskipun server Anda macet, gunakan langkah-langkah berikut:

  1. gunakan node cluster untuk melakukan beberapa proses per core. Jadi jika satu proses mati, proses lain akan otomatis boot up. Periksa: http://nodejs.org/api/cluster.html

  2. gunakan domain untuk menangkap operasi async alih-alih menggunakan try-catch atau tidak tertangkap. Saya tidak mengatakan bahwa mencoba-tangkap atau tidak tertangkap adalah pikiran buruk!

  3. gunakan selamanya / supervisor untuk memantau layanan Anda

  4. tambahkan daemon untuk menjalankan aplikasi simpul Anda: http://upstart.ubuntu.com

semoga ini membantu!

Nam Nguyen
sumber
4

Cobalah untuk mencoba modul simpul PM2 itu jauh konsisten dan memiliki dokumentasi yang bagus. Manajer proses produksi untuk aplikasi Node.js dengan penyeimbang beban bawaan. harap hindari uncaughtException untuk masalah ini. https://github.com/Unitech/pm2

Virendra Rathore
sumber
`restart aplikasi Anda setelah setiap pengecualian yang tidak ditangani!` Jika seandainya 2000 pengguna menggunakan server web node untuk streaming video dan 1 pengguna mendapat pengecualian maka memulai ulang tidak akan mengganggu semua pengguna lain?
Vikas Bansal
Saya sangat senang ketika saya menemukan PM2. software hebat
Mladen Janjetovic
0

UncaughtException adalah "mekanisme yang sangat kasar" (sangat benar) dan domain sudah tidak digunakan lagi. Namun, kami masih memerlukan beberapa mekanisme untuk menangkap kesalahan di sekitar domain (logis). Perpustakaan:

https://github.com/vacuumlabs/yacol

dapat membantu Anda melakukan ini. Dengan sedikit tulisan tambahan, Anda dapat memiliki semantik domain yang bagus di sekitar kode Anda!

Tomas Kulich
sumber
0

Bekerja dengan baik pada restify:

server.on('uncaughtException', function (req, res, route, err) {
  log.info('******* Begin Error *******\n%s\n*******\n%s\n******* End Error *******', route, err.stack);
  if (!res.headersSent) {
    return res.send(500, {ok: false});
  }
  res.write('\n');
  res.end();
});
PH Andrade
sumber