Node.js dosyasının kilitlenmesini nasıl önleyebilirim? try-catch çalışmıyor


157

Deneyimlerime göre, bir php sunucusu günlüğe veya sunucu sonuna bir istisna atar, ancak node.js sadece çöker. Kodumu bir try-catch ile çevrelemek de herşeyi eşzamansız yapıldığı için çalışmaz. Üretim sunucularında herkesin ne yaptığını bilmek istiyorum.

Yanıtlar:


132

Http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception adresindeki Node'nin kendi belgelerinde okuyabileceğiniz için diğer cevaplar gerçekten delilik.

Birisi belirtilen diğer yanıtları kullanıyorsa Düğüm Dokümanları'nı okuyun:

Bunun uncaughtExceptionistisna yönetimi için çok kaba bir mekanizma olduğunu ve gelecekte kaldırılabileceğini unutmayın

PM2

Her şeyden önce, ben çok yükleme öneriyoruz PM2için Node.js. PM2, yük dengelemenin yanı sıra kilitlenme ve Düğüm uygulamalarını izleme konusunda gerçekten harika. PM2, Düğüm uygulamasını her kilitlendiğinde, herhangi bir nedenle durduğunda veya sunucu yeniden başlatıldığında hemen başlatır. Yani, bir gün kodumuzu yönettikten sonra bile, uygulama çökerse, PM2 hemen başlatabilir. Daha fazla bilgi için PM2'yi Yükleme ve Çalıştırma

Şimdi uygulamanın çökmesini önlemek için çözümümüze geri dönüyor.

Sonuç olarak, sonunda Düğüm belgesinin kendisinin önerdiği şeyi buldum:

Kullanmayın uncaughtException, bunun yerine domainsile clusterkullanın. Eğer kullanımını yaparsanız uncaughtException, her işlenmeyen istisna sonra uygulamayı yeniden başlatın!

Küme ile DOMAIN

Gerçekte yaptığımız şey, hatayı tetikleyen talebe bir hata yanıtı göndermek ve diğerlerinin normal zamanlarında bitmesini sağlamak ve bu çalışandaki yeni istekleri dinlemeyi bırakmak.

Bu şekilde, ana işlem, bir çalışan bir hatayla karşılaştığında yeni bir çalışanı çatallayabildiğinden, küme modülü ile el ele gider. Ne demek istediğimi anlamak için aşağıdaki koda bakın

Kullanarak Domainve programımızı kullanarak birden çok çalışan işlemine ayırmanın esnekliğini kullanarak Cluster, daha uygun şekilde tepki verebilir ve hataları çok daha güvenli bir şekilde ele alabiliriz.

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);
} 

Kullanımdan Domainkaldırılmayı bekliyor olsa da ve yeni değiştirme Düğüm Belgeleri'nde belirtildiği gibi kaldırılacak olsa da

Bu modül kullanımdan kaldırılmayı bekliyor. Yeni bir API sonlandırıldığında, bu modül tamamen kullanımdan kaldırılacaktır. Etki alanlarının sağladığı işlevselliğe kesinlikle sahip olması gereken kullanıcılar şimdilik buna güvenebilir, ancak gelecekte farklı bir çözüme geçmeleri beklenir.

Ancak yeni değiştirme başlatılıncaya kadar, Küme ile Etki Alanı Düğüm Belgelerinin önerdiği tek iyi çözümdür.

Derinlemesine anlama Domainve Clusterokuma için

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

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

@Stanley Luo'ya Küme ve Etki Alanları hakkındaki bu harika ayrıntılı açıklamayı paylaştığı için teşekkürler

Küme ve Etki Alanları


9
Uyarı: Etki alanı kullanımdan kaldırılmayı bekliyor: bağlantı . Düğüm belgelerinden önerilen yöntem cluster: bağlantısını kullanmaktır .
Paul

4
restart your application after every unhandled exception!2000 kullanıcının video akışı için bir düğüm web sunucusu kullanması ve 1 kullanıcının bir istisnası olması durumunda, yeniden başlatma diğer tüm kullanıcıları kesintiye uğratmaz?
Vikas Bansal

2
@VikasBansal Evet o istek mutlaka kullanıcılar ve kullanımı kötü olmasının nedeni bu en hepsi kesme uncaughtExceptionve kullanım Domainile Clusteryerine öylesine bir kullanıcı yüzden sadece onun iplik kümesinden kaldırılır ve onun için yeni bir tane oluşturulur bir istisna ile karşı karşıya eğer. Düğüm sunucunuzu da yeniden başlatmanız gerekmez. Diğer taraftan uncaughtException, kullanıcı herhangi bir sorunla karşılaştığınızda sunucunuzu yeniden başlatmanız gerekir. Bu nedenle Etki Alanı'nı Küme ile kullanın.
Havadar

3
domaintamamen kullanımdan kaldırıldığında ve kaldırıldığında ne yapmalıyız ?
Jas

3
Bu öğreticiyi şu kavramları anlamayanlar için buldumcluster ve workers: sitepoint.com/…
Stanley Luo

81

Bu kodu doğru ifadelerimin ve genel bildirimlerimin altına koydum:

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

benim için çalışıyor. Bu konuda sevmediğim tek şey, sadece bir şeyin çökmesine izin verirsem alacağım kadar bilgi almam.


45
Dikkat edilmesi gereken bir nokta: Bu yöntem iyi çalışıyor, ancak TÜM HTTP yanıtlarının düzgün bir şekilde sonlandırılması gerektiğini unutmayın. Başka bir deyişle, bir HTTP isteğini işlerken yakalanmamış bir özel durum oluşursa, yine de http.ServerResponse Nesnesinde end () öğesini çağırmanız gerekir. Ancak bunu siz uygularsınız. Bunu yapmazsanız, tarayıcı vazgeçene kadar istek askıda kalır. Bu isteklerden yeterince fazlasına sahipseniz, sunucuda bellek kalmayabilir.
BMiner

3
@BMiner, daha iyi bir uygulama sağlayabilir misiniz? Bu sorunu (istek asılı) fark ettim, bu gerçekten sadece sunucuyu foreverya da bir şeyi kullanarak yeniden başlatmaktan daha iyi değil .
pixelfreak

6
Bu derin bir açıklama gerektirir. Bunun berbat olduğunu biliyorum, ancak yakalanmayan bir istisna olduğunda, sunucunuzun ASAP'yi yeniden başlatması gerekiyor. Gerçekten, 'uncaughtException' Etkinliğinin amacı, bir uyarı e-postası göndermek için bir fırsat olarak kullanmak ve daha sonra process.exit (1) kullanmaktır; sunucuyu kapatmak için. Sunucuyu yeniden başlatmak için sonsuza dek veya bunun gibi bir şey kullanabilirsiniz. Bekleyen HTTP istekleri zaman aşımına uğrar ve başarısız olur. Kullanıcılarınız size kızacak. Ancak, bu en iyi çözümdür. Neden soruyorsun? Çıkış stackoverflow.com/questions/8114977/…
BMiner

3
Yakalanmayan hatadan daha fazla bilgi almak için şunu kullanın: console.trace (err.stack);
Jesse Dunlap

2
UYARI: Düğümün belgeleri, belirsiz terimlerle, bunu asla çılgınca tehlikeli olduğu için yapmamanız gerektiğini söylüyor: nodejs.org/api/process.html#process_event_uncaughtexception
Jeremy Logan

28

Belirtildiği gibi burada bulacağınız error.stackbu tür hataya neden çizgi sayısı olarak daha eksiksiz bir hata mesajı sunar:

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

12

Deneyin supervisor

npm install supervisor
supervisor app.js

Veya yükleyebilirsiniz forever bunun yerine .

Tek yapmanız gereken, sunucunuzu yeniden başlatarak çöktüğünde kurtarmaktır.

forever çökmekte olan işlemleri incelikle kurtarmak için kod içinde kullanılabilir.

foreverDocs programlı işleme çıkış / hata katı bilgiye sahip.


9
Şüphesiz bu çözüm olamaz ... Sunucunun kapalı olduğu zamanda yeni gelen isteklere yanıt veremez. Uygulama kodundan bir istisna atılabilir - sunucunun sadece çökmemesi ve yeniden başlatılmasını umması değil, 500 hatayla yanıt vermesi gerekir.
Ant Kutschera

20
Bir hacker olarak, sunucuya basit bir istek göndermeleri ve bir istek parametresini kaçırmaları gerektiği anlaşılabilir - bu, javascriptte node.js'nin çökmesine neden olan bir undef'e yol açar. Önerinle tüm kümeni tekrar tekrar öldürebilirim. Yanıt, uygulamanın zarif bir şekilde başarısız olmasını sağlamaktır - yani yakalanmayan istisnayı ele almak ve çökmemek. sunucu çok sayıda voip oturumu yapıyordu? çökmesi ve yakılması ve mevcut tüm oturumların onunla ölmesi kabul edilemez. kullanıcılarınız yakında ayrılır.
Ant Kutschera

5
@AntKutschera bu yüzden istisnalar istisnai durumlar olmalıdır. İstisnalar sadece durumlarda tetiklenmesi gereken olamaz kurtarmak ve süreç nereye sahiptir çökmesine. Bu istisnai durumları ele almak için başka araçlar kullanmalısınız . Ama ne demek istediğini anlıyorum. Mümkün olan yerlerde incelikle başarısız olmalısınız. Bununla birlikte, bozuk bir duruma devam etmenin daha fazla hasar vereceği durumlar vardır.
Raynos

2
Evet, burada farklı düşünce okulları var. Bunu öğrendiğim gibi (Javascript yerine Java), beklemeniz gereken kabul edilebilir beklentiler vardır, belki de iş istisnaları olarak bilinir ve sonra bellek dışında olduğu gibi kurtarmayı beklememeniz gereken çalışma zamanı istisnaları veya hataları vardır. Zarif bir şekilde başarısız olmama ile ilgili bir sorun, yazdığım bazı kütüphanenin kurtarılabilir bir şey durumunda bir istisna attığını beyan edebileceği, bir kullanıcının girdilerini nerede düzeltebileceğini söyleyebilmesidir. Uygulamanızda, benim belgeleri okumak ve sadece kullanıcı kurtarmak mümkün olabilir, çökme
Ant Kutschera

1
@AntKutschera Bu nedenle istisnaları kaydediyoruz. Üretim günlüklerinizi genel istisnalar için analiz etmeli ve sunucunun çökmesine izin vermek yerine bunlardan nasıl kurtulabileceğinizi ve nasıl kurtarabileceğinizi bulmalısınız. Bu metodolojiyi PHP, Ruby on Rails ve Node ile kullandım. Bir işlemden çıkıp çıkmamanıza bakılmaksızın, her 500 hatası attığınızda kullanıcılarınıza bir kötülük yaparsınız. Bu JavaScript veya Düğüme özgü uygulama değildir.
Eric Elliott

7

Try-catch kullanmak yakalanmayan hataları çözebilir, ancak bazı karmaşık durumlarda, zaman uyumsuz işlevi yakalamak gibi işi doğru yapmayacaktır. Düğümde, herhangi bir eşzamansız işlev çağrısının potansiyel bir uygulama kilitlenme işlemi içerebileceğini unutmayın.

Kullanmak uncaughtExceptionbir çözümdür, ancak verimsiz olarak kabul edilir ve Düğümün gelecekteki sürümlerinde kaldırılması muhtemeldir, bu nedenle buna güvenmeyin.

İdeal çözüm etki alanı kullanmaktır: http://nodejs.org/api/domain.html

Uygulamanızın çalıştığından ve sunucunuzun çökmesine rağmen çalıştığından emin olmak için aşağıdaki adımları kullanın:

  1. çekirdek başına birden çok işlemi çatallamak için düğüm kümesi kullanın. Yani bir süreç ölürse, başka bir süreç otomatik olarak başlatılır. Kontrol et: http://nodejs.org/api/cluster.html

  2. try-catch veya uncaught kullanmak yerine zaman uyumsuz işlemi yakalamak için domain'i kullanın. Try-catch veya yakalanmamış kötü düşünce olduğunu söylemiyorum!

  3. hizmetlerinizi izlemek için sonsuza dek / süpervizör kullanın

  4. düğüm uygulamanızı çalıştırmak için arka plan programı ekleyin: http://upstart.ubuntu.com

Bu yardımcı olur umarım!


4

PM2 düğüm modülüne bir deneyin, çok tutarlı ve harika belgelere sahip. Yerleşik yük dengeleyicili Node.js uygulamaları için üretim süreç yöneticisi. lütfen bu sorun için uncaughtException özel durumundan kaçının. https://github.com/Unitech/pm2


`` işlenmeyen her istisnadan sonra uygulamanızı yeniden başlatın! '' 2000 kullanıcının video akışı için bir düğüm web sunucusu kullanması ve 1 kullanıcının bir istisnası olması durumunda, yeniden başlatma diğer tüm kullanıcıları kesintiye uğratmayacak mı?
Vikas Bansal

PM2'yi keşfettiğimde çok mutlu oldum. harika bir yazılım parçası
Mladen Janjetovic

0

UncaughtException "çok kaba bir mekanizmadır" (çok doğru) ve alanlar artık kullanımdan kaldırıldı. Ancak yine de (mantıksal) alanlardaki hataları yakalamak için bazı mekanizmalara ihtiyacımız var. Kütüphane:

https://github.com/vacuumlabs/yacol

bunu yapmanıza yardımcı olabilir. Biraz ekstra yazma ile kodunuzun her yerinde güzel bir alan semantiği olabilir!


0

Restify üzerinde harika çalışıyor:

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();
});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.