Làm cách nào để gỡ lỗi ECONNRESET trong Node.js?


288

Tôi đang chạy một ứng dụng Express.js bằng cách sử dụng Socket.io cho một ứng dụng web trò chuyện và tôi nhận được lỗi sau đây ngẫu nhiên khoảng 5 lần trong 24 giờ. Quá trình nút được gói trong mãi mãi và nó tự khởi động lại ngay lập tức.

Vấn đề là việc khởi động lại Express khiến người dùng của tôi rời khỏi phòng của họ và không ai muốn điều đó.

Máy chủ web được ủy quyền bởi HAProxy. Không có vấn đề ổn định ổ cắm, chỉ sử dụng vận chuyển websockets và flashsockets. Tôi không thể tái tạo điều này trên mục đích.

Đây là lỗi với Node v0.10.11:

    events.js:72
            throw er; // Unhandled 'error' event
                  ^
    Error: read ECONNRESET     //alternatively it s a 'write'
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)
    error: Forever detected script exited with code: 8
    error: Forever restarting script for 2 time

EDIT (2013-07-22)

Đã thêm cả trình xử lý lỗi máy khách socket.io và trình xử lý ngoại lệ chưa được lưu. Có vẻ như điều này bắt lỗi:

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

Vì vậy, tôi nghi ngờ đây không phải là sự cố của Socket.io mà là yêu cầu HTTP đến một máy chủ khác mà tôi thực hiện hoặc kết nối MySQL / Redis. Vấn đề là ngăn xếp lỗi không giúp tôi xác định được vấn đề về mã của mình. Đây là đầu ra nhật ký:

    Error: read ECONNRESET
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)

Làm thế nào để tôi biết những gì gây ra điều này? Làm thế nào để tôi nhận được nhiều hơn từ lỗi?

Ok, không dài dòng lắm nhưng đây là stacktrace với Longjohn:

    Exception caught: Error ECONNRESET
    { [Error: read ECONNRESET]
      code: 'ECONNRESET',
      errno: 'ECONNRESET',
      syscall: 'read',
      __cached_trace__:
       [ { receiver: [Object],
           fun: [Function: errnoException],
           pos: 22930 },
         { receiver: [Object], fun: [Function: onread], pos: 14545 },
         {},
         { receiver: [Object],
           fun: [Function: fireErrorCallbacks],
           pos: 11672 },
         { receiver: [Object], fun: [Function], pos: 12329 },
         { receiver: [Object], fun: [Function: onread], pos: 14536 } ],
      __previous__:
       { [Error]
         id: 1061835,
         location: 'fireErrorCallbacks (net.js:439)',
         __location__: 'process.nextTick',
         __previous__: null,
         __trace_count__: 1,
         __cached_trace__: [ [Object], [Object], [Object] ] } }

Ở đây tôi phục vụ tệp chính sách ổ cắm flash:

    net = require("net")
    net.createServer( (socket) =>
      socket.write("<?xml version=\"1.0\"?>\n")
      socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
      socket.write("<cross-domain-policy>\n")
      socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
      socket.write("</cross-domain-policy>\n")
      socket.end()
    ).listen(843)

Đây có thể là nguyên nhân?


3
@GottZ có lẽ điều này có thể giúp (nói chuyện với ai đó làm việc trong nút js) gist.github.com/samsonradu/1b0c6feb438f5a53e30e . Tôi sẽ triển khai trình xử lý socket.error ngay hôm nay và cho bạn biết.
Samson

1
@Gottz xử lý socket.error không giúp được gì, nhưng process.on ('unsaughtException') bắt lỗi. Đây là console.log của lỗi: {[Lỗi: ECONNRESET đọc] code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'đọc'}
Samson

1
ECONNRESET có thể là do sự cố mạng. Như bạn biết, không thể bắt tất cả các ngoại lệ khi thử nghiệm. Một số sẽ hiển thị trên máy chủ sản xuất của bạn. Bạn sẽ phải làm cho máy chủ của bạn mạnh mẽ. Bạn có thể xử lý việc xóa phiên bằng cách sử dụng Redis làm bộ lưu trữ. Nó làm cho các phiên của bạn tồn tại ngay cả sau khi máy chủ nút của bạn ngừng hoạt động.
dùng568109

1
Tại sao điều đó có liên quan đến việc xóa phiên? Chúng được xử lý bởi Redis.
Samson

3
Bạn có ít nhất một ổ cắm TCP nghe mà không có bộ xử lý. Vì vậy, bây giờ là lúc để kiểm tra xem cái đó ở đâu: D
Rêu

Câu trả lời:


253

Bạn có thể đã đoán nó rồi: đó là lỗi kết nối.

"ECONNRESET" có nghĩa là phía bên kia của cuộc trò chuyện TCP đột ngột đóng kết thúc kết nối. Điều này rất có thể là do một hoặc nhiều lỗi giao thức ứng dụng. Bạn có thể nhìn vào nhật ký máy chủ API để xem nó có phàn nàn về điều gì không.

Nhưng vì bạn cũng đang tìm cách kiểm tra lỗi và có khả năng gỡ lỗi, nên bạn hãy xem " Cách gỡ lỗi ổ cắm bị treo trong NodeJS? " Được đăng tại stackoverflow liên quan đến câu hỏi tương tự.

Giải pháp nhanh và bẩn cho sự phát triển :

Sử dụng longjohn , bạn nhận được dấu vết ngăn xếp dài sẽ chứa các hoạt động không đồng bộ.

Giải pháp sạch và đúng : Về mặt kỹ thuật, trong nút, bất cứ khi nào bạn phát ra một 'error'sự kiện và không ai nghe nó, nó sẽ ném . Để làm cho nó không ném, đặt một người nghe vào nó và tự xử lý nó. Bằng cách đó bạn có thể đăng nhập lỗi với nhiều thông tin hơn.

Để có một người nghe cho một nhóm các cuộc gọi, bạn có thể sử dụng các tên miền và cũng có thể bắt các lỗi khác trong thời gian chạy. Đảm bảo rằng mỗi hoạt động không đồng bộ liên quan đến http (Máy chủ / Máy khách) nằm trong ngữ cảnh miền khác nhau so với các phần khác của mã, tên miền sẽ tự động lắng nghe các errorsự kiện và sẽ truyền nó đến trình xử lý riêng của nó. Vì vậy, bạn chỉ nghe trình xử lý đó và nhận dữ liệu lỗi. Bạn cũng có thêm thông tin miễn phí.

EDIT (2013-07-22)

Như tôi đã viết ở trên:

"ECONNRESET" có nghĩa là phía bên kia của cuộc trò chuyện TCP đột ngột đóng kết thúc kết nối. Điều này rất có thể là do một hoặc nhiều lỗi giao thức ứng dụng. Bạn có thể nhìn vào nhật ký máy chủ API để xem nó có phàn nàn về điều gì không.

Điều gì cũng có thể là trường hợp: tại thời điểm ngẫu nhiên, phía bên kia bị quá tải và kết quả là giết chết kết nối. Nếu đúng như vậy, tùy thuộc vào những gì bạn đang kết nối với chính xác

Nhưng một điều chắc chắn: bạn thực sự có lỗi đọc trên kết nối TCP của bạn, điều này gây ra ngoại lệ. Bạn có thể thấy điều đó bằng cách xem mã lỗi bạn đã đăng trong bản chỉnh sửa của mình, xác nhận nó.


Nó không có nghĩa là 'đóng cửa đột ngột'. Nó thường là kết quả của việc ghi vào một kết nối mà ngang hàng đã đóng bình thường. Điều đó sẽ khiến nó đưa ra một RST.
Hầu tước Lorne

1
@EJP Có một lý do chính đáng tại sao tôi đã viết ra một cách đột ngột. Lỗi (không cảnh báo) cho biết kết nối đã được đặt lại bởi ngang hàng. Một kết nối hiện có đã bị đóng bởi các đồng nghiệp từ xa. Một sự ép buộc là đột ngột kể từ khi bất ngờ! (Điều này thường xảy ra nếu ứng dụng ngang hàng trên máy từ xa bị dừng đột ngột, máy được khởi động lại hoặc ứng dụng ngang hàng đã sử dụng "đóng cứng" trên ổ cắm từ xa. Lỗi này cũng có thể xảy ra nếu kết nối bị hỏng do hoạt động "giữ mạng" phát hiện lỗi trong khi một hoặc nhiều hoạt động đang diễn ra. Các hoạt động này và các hoạt động tiếp theo sẽ thất bại.)
e-sushi

2
Tôi nhận được lỗi này khi tôi gửi hàng loạt khoảng 100 cuộc gọi API gần như đồng thời từ trình duyệt (Chrome) để kiểm tra. Tôi tưởng tượng rằng Chrome sau đó phải trở nên quá tải và giết một số kết nối ... @Samson - có gì sai khi xử lý từng yêu cầu trong miền của chính nó và bắt lỗi miền mà không khởi động lại máy chủ?
supershnee

2
@supershnee Bạn hầu như luôn phải khởi động lại máy chủ của mình sau một ngoại lệ chưa được phát hiện do dữ liệu, ứng dụng và node.js của bạn ở trạng thái không xác định. Tiếp tục sau một ngoại lệ khiến dữ liệu của bạn gặp rủi ro. Nếu bạn muốn tìm hiểu thêm, hãy xem tài liệu của Node về quy trình hoặc tài liệu của Node trên các miền .
c1moore

39

Một máy chủ tcp đơn giản mà tôi có để phục vụ tệp chính sách flash đã gây ra điều này. Bây giờ tôi có thể bắt lỗi bằng trình xử lý:

# serving the flash policy file
net = require("net")

net.createServer((socket) =>
  //just added
  socket.on("error", (err) =>
    console.log("Caught flash policy server socket error: ")
    console.log(err.stack)
  )

  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)

2
Có bất cứ điều gì sai với mã? Tôi có nên kiểm tra xem ổ cắm có thể ghi được trước khi viết không?
Samson

Doh, không thấy rằng bạn đã tìm thấy giải pháp trước khi tôi đăng khá nhiều điều tương tự :) Mặc dù vậy, ngay cả khi bạn kiểm tra xem ổ cắm có thể ghi được hay không, có thể không phải là khi bạn viết cho nó sau vài giây và vẫn sẽ đưa ra một lỗi, vì vậy đây là "cách" để chắc chắn.
Joachim Isaksson

ok, và có một lối thoát an toàn nếu điều này? như socket.close () bên trong bộ xử lý lỗi? bởi vì tôi nghĩ rằng tải CPU của tôi đang tăng sau những lỗi này (không chắc chắn)
Samson

2
Tôi đã luôn gọi socket.destroy()trình xử lý lỗi để đảm bảo. Đáng buồn là tôi không thể tìm thấy tài liệu cho dù nó là bắt buộc, nhưng nó không phát ra lỗi để làm như vậy.
Joachim Isaksson

socket.destroy () đã lưu ngày của tôi, bất cứ điều gì nó hoạt động !! Cảm ơn bạn!
Firas Abd Alrahman

27

Tôi gặp vấn đề tương tự khi các ứng dụng bắt đầu bị lỗi sau khi nâng cấp Node. Tôi tin rằng điều này có thể được truy trở lại để phát hành Node v0.9.10 mục này:

  • net: không triệt tiêu ECONNRESET (Ben Noordhuis)

Các phiên bản trước sẽ không lỗi khi bị gián đoạn từ máy khách. Việc ngắt kết nối từ máy khách sẽ gây ra lỗi ECONNRESET trong Nút. Tôi tin rằng đây là chức năng dành cho Node, vì vậy cách khắc phục (ít nhất là đối với tôi) là xử lý lỗi, điều mà tôi tin rằng bạn đã làm trong các trường hợp ngoại lệ. Mặc dù tôi xử lý nó trong trình xử lý net.socket.

Bạn có thể chứng minh điều này:

Tạo một máy chủ ổ cắm đơn giản và nhận Node v0.9.9 và v0.9.10.

require('net')
    .createServer( function(socket) 
    {
           // no nothing
    })
    .listen(21, function()
     {
           console.log('Socket ON')
    })

Khởi động nó bằng v0.9.9 và sau đó thử FTP sang máy chủ này. Tôi chỉ sử dụng FTP và cổng 21 vì tôi đang dùng Windows và có máy khách FTP, nhưng không có ứng dụng khách telnet nào tiện dụng.

Sau đó từ phía khách hàng, chỉ cần ngắt kết nối. (Tôi chỉ đang làm Ctrl-C)

Bạn sẽ thấy NO ERROR khi sử dụng Node v0.9.9 và ERROR khi sử dụng Node v.0.9.10 trở lên.

Trong sản xuất, tôi sử dụng v.0.10. một cái gì đó và nó vẫn đưa ra lỗi. Một lần nữa, tôi nghĩ rằng điều này được dự định và giải pháp là xử lý lỗi trong mã của bạn.


3
Cảm ơn, tôi tự đóng đinh nó! Điều quan trọng là không để lỗi lan truyền sang unsaughtException vì nó làm cho toàn bộ ứng dụng không ổn định. Ví dụ: sau khi bắt được khoảng 10 lỗi ECONNRESET, máy chủ đôi khi không phản hồi (chỉ bị đóng băng và không xử lý bất kỳ kết nối nào)
Samson

Cũng biết về thay đổi phiên bản nút không khắc phục được lỗi nữa, nhưng thấy rất nhiều vấn đề hiển thị và được giải quyết mỗi phiên bản, tôi không muốn tìm phiên bản mới nhất. Tôi đang sử dụng V0.10.13 bây giờ btw
Samson

16

Có vấn đề tương tự ngày hôm nay. Sau một số nghiên cứu, tôi tìm thấy một --abort-on-uncaught-exceptiontùy chọn node.js rất hữu ích . Nó không chỉ cung cấp nhiều dấu vết ngăn xếp và lỗi hữu ích hơn nhiều, mà còn lưu tệp lõi khi sự cố ứng dụng cho phép gỡ lỗi thêm.


4
Thật kỳ lạ khi một câu trả lời mới cho câu hỏi cũ này sẽ xuất hiện khi tôi đang tìm kiếm - nhưng điều này thật tuyệt, cảm ơn
Dấu chấm phẩy

13

Tôi đã phải đối mặt với cùng một vấn đề nhưng tôi đã giảm nhẹ nó bằng cách đặt:

server.timeout = 0;

trước server.listen. serverlà một máy chủ HTTP ở đây. Thời gian chờ mặc định là 2 phút theo tài liệu API .


5
Đây không phải là một giải pháp mà là một quickfix sẽ phá vỡ mọi thứ mà không gây ra lỗi.
Nishant Ghodke

9

Một trường hợp có thể khác (nhưng hiếm) có thể là nếu bạn có máy chủ liên lạc với máy chủ và đã đặt server.maxConnections ở giá trị rất thấp.

Trong lõi lib của mạng, nó sẽ gọi clientHandle.close()nó cũng sẽ gây ra lỗi ECONNRESET:

if (self.maxConnections && self._connections >= self.maxConnections) {
  clientHandle.close(); // causes ECONNRESET on the other end
  return;
}

Cuộc gọi tuyệt vời, nhưng maxConnectionsgiá trị mặc định là Infinity. Đây chỉ là trường hợp (như bạn đã nói) nếu bạn đã ghi đè rõ ràng giá trị đó.
Gajus

7

Có, việc phục vụ tệp chính sách của bạn chắc chắn có thể gây ra sự cố.

Để lặp lại, chỉ cần thêm một độ trễ cho mã của bạn:

net.createServer( function(socket) 
{
    for (i=0; i<1000000000; i++) ;
    socket.write("<?xml version=\"1.0\"?>\n");

… Và sử dụng telnet để kết nối với cổng. Nếu bạn ngắt kết nối telnet trước khi hết thời gian trễ, bạn sẽ gặp sự cố (ngoại lệ chưa được xử lý) khi socket.write gây ra lỗi.

Để tránh sự cố ở đây, chỉ cần thêm một trình xử lý lỗi trước khi đọc / ghi ổ cắm:

net.createServer(function(socket)
{
    for(i=0; i<1000000000; i++);
    socket.on('error', function() { console.log("error"); });
    socket.write("<?xml version=\"1.0\"?>\n");
}

Khi bạn thử ngắt kết nối ở trên, bạn sẽ chỉ nhận được một thông điệp tường trình thay vì sự cố.

Và khi bạn đã hoàn tất, hãy nhớ loại bỏ sự chậm trễ.


6

Tôi cũng gặp lỗi ECONNRESET trong quá trình phát triển, cách tôi giải quyết là không sử dụng gật đầu để khởi động máy chủ của mình, chỉ sử dụng "node server.js"để khởi động máy chủ của tôi đã khắc phục sự cố của tôi.

Thật kỳ lạ, nhưng nó đã làm việc với tôi, bây giờ tôi không bao giờ thấy lỗi ECONNRESET nữa.


4

Tôi cũng gặp lỗi này và đã có thể giải quyết nó sau nhiều ngày gỡ lỗi và phân tích:

giải pháp của tôi

Đối với tôi VirtualBox (đối với Docker) là vấn đề. Tôi đã cấu hình Cổng chuyển tiếp trên máy ảo của mình và lỗi chỉ xảy ra trên cổng chuyển tiếp.

kết luận chung

Những quan sát sau đây có thể giúp bạn tiết kiệm được nhiều ngày làm việc mà tôi phải đầu tư:

  • Đối với tôi, sự cố chỉ xảy ra trên các kết nối từ localhost đến localhost trên một cổng. -> kiểm tra thay đổi bất kỳ hằng số nào trong số này để giải quyết vấn đề.
  • Đối với tôi, sự cố chỉ xảy ra trên máy của tôi -> hãy để người khác thử.
  • Đối với tôi, vấn đề chỉ xảy ra sau một thời gian và không thể được sao chép một cách đáng tin cậy
  • Vấn đề của tôi không thể được kiểm tra với bất kỳ công cụ nút hoặc biểu thức (gỡ lỗi-) nào. -> đừng lãng phí thời gian vào việc này

-> tìm hiểu xem có thứ gì đó đang gây rối với mạng của bạn (cài đặt), như VM, Tường lửa, v.v., đây có lẽ là nguyên nhân của vấn đề.


2

Tôi đã giải quyết vấn đề bằng cách kết nối với một mạng khác . Đó là một trong những vấn đề có thể xảy ra.

Như đã thảo luận ở trên, ECONNRESET có nghĩa là cuộc hội thoại TCP đột ngột đóng kết thúc kết nối.

Kết nối internet của bạn có thể ngăn bạn kết nối với một số máy chủ. Trong trường hợp của tôi, tôi đã cố gắng kết nối với mLab (dịch vụ cơ sở dữ liệu đám mây lưu trữ cơ sở dữ liệu MongoDB). Và ISP của tôi đang chặn nó.


Cái này hoạt động với tôi, mã của tôi đang hoạt động tốt trong vài giờ trở lại đột nhiên ngừng hoạt động, hóa ra, sự thay đổi mạng đã gây ra sự cố
Aklank Jain

2

Tôi đã giải quyết vấn đề này bằng cách:

  • Tắt kết nối wifi / ethernet của tôi và bật.
  • Tôi gõ: npm updatetrong terminal để cập nhật npm.
  • Tôi đã cố gắng đăng xuất khỏi phiên và đăng nhập lại

Sau đó tôi đã thử lệnh npm tương tự và điều tốt là nó đã hoạt động. Tôi không chắc nó đơn giản đến thế.

Tôi đang sử dụng CENTOS 7


0

Tôi đã có cùng một vấn đề và có vẻ như phiên bản Node.js là vấn đề.

Tôi đã cài đặt phiên bản Node.js trước đó (10.14.2) và mọi thứ đều ổn khi sử dụng nvm (cho phép bạn cài đặt một số phiên bản Node.js và nhanh chóng chuyển từ phiên bản này sang phiên bản khác).

Nó không phải là một giải pháp "sạch", nhưng nó có thể phục vụ bạn tạm thời.


0

Tôi chỉ cần tìm ra điều này, ít nhất là trong trường hợp sử dụng của tôi.

Tôi đã nhận được ECONNRESET. Hóa ra là cách mà máy khách của tôi được thiết lập, nó đã tấn công máy chủ bằng một lệnh gọi API rất nhiều lần - và nó chỉ cần chạm vào điểm cuối một lần.

Khi tôi sửa nó, lỗi đã biến mất.


-2

Hãy thử thêm các tùy chọn này vào socket.io:

const options = { transports: ['websocket'], pingTimeout: 3000, pingInterval: 5000 };

Tôi hy vọng điều này sẽ giúp bạn !

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.