Tedious: ConnectionError: μ—°κ²° λŠκΉ€ - κΈ΄ λ¬Έμžμ—΄μ„ μ‚½μž…ν•  λ•Œ ECONNRESET μ“°κΈ°

에 λ§Œλ“  2019λ…„ 07μ›” 16일  Β·  9μ½”λ©˜νŠΈ  Β·  좜처: tediousjs/tedious

Azure SQL Database에 ν…Œμ΄λΈ”μ΄ μžˆμŠ΅λ‹ˆλ‹€.

CREATE TABLE [dbo].[Owner](
    [OwnerId] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Name] [varchar](50) NOT NULL,
    [Signature] [varchar](max) NULL
)

μ„œλͺ… 열에 맀우 κΈ΄ λ¬Έμžμ—΄μ„ μ‚½μž…ν•˜λ €κ³  ν–ˆμŠ΅λ‹ˆλ‹€. packetSizeκ°€ 16384 μ΄μƒμœΌλ‘œ μ„€μ •λ˜μ–΄ μžˆμ§€ μ•ŠμœΌλ©΄ λ‹€μŒ μ˜ˆμ™Έκ°€ λ°œμƒν•©λ‹ˆλ‹€.

ConnectionError: Connection lost - write ECONNRESET
    at ConnectionError (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\errors.js:13:12)
    at Connection.socketError (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1187:26)
    at Socket.<anonymous> (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1032:14)
    at Socket.emit (events.js:205:15)
    at errorOrDestroy (internal/streams/destroy.js:107:12)
    at onwriteError (_stream_writable.js:438:5)
    at onwrite (_stream_writable.js:459:5)
    at internal/streams/destroy.js:49:7
    at Socket._destroy (net.js:593:3)
    at Socket.destroy (internal/streams/destroy.js:37:8)
Emitted 'error' event at:
    at Connection.socketError (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1187:12)
    at Socket.<anonymous> (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1032:14)
    [... lines matching original stack trace ...]
    at Socket.destroy (internal/streams/destroy.js:37:8)
    at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:84:12) {
  message: 'Connection lost - write ECONNRESET',
  code: 'ESOCKET'
}

μ•„λž˜λŠ” λ‚΄ κ°„λ‹¨ν•œ ν…ŒμŠ€νŠΈ ν”„λ‘œκ·Έλž¨μž…λ‹ˆλ‹€. λ‚˜λŠ” μ΅œμ‹  μ§€λ£¨ν•œμ„ μ‚¬μš©ν•©λ‹ˆλ‹€. λ˜ν•œ 읽기 μž‘μ—…μ€ νŒ¨ν‚· 크기에 관계없이 κΈ΄ λ¬Έμžμ—΄μ— λŒ€ν•΄ 잘 μž‘λ™ν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. λ‚΄κ°€ 뭘 잘λͺ»ν–ˆλŠ”지 μ•Œμ•„?

var Connection = require('tedious').Connection;

var config = {
  server: "myserver.database.windows.net",
  options: {
    encrypt: true,
    database: "<mydb>",
    packetSize: 4096,
  },
  authentication: {
    type: "default",
    options: {  
      userName: "<myuser>",
      password: "<mypwd>",
    }
  }
};

var connection = new Connection(config);

connection.on('connect', function(err) {
    // executeStatement();
    executeInsert();
  }
);


var Request = require('tedious').Request;

function executeStatement() {
  /* Read a long string, work fine */
  request = new Request("select OwnerId, Signature From dbo.Owner Where OwnerId = 36", function(err, rowCount) {
    if (err) {
      console.log(err);
    } else {
      console.log(rowCount + ' rows');
    }
  });

  request.on('row', function(columns) {
    columns.forEach(function(column) {
      console.log(column.value);
    });
  });

  connection.execSql(request);
}


function executeInsert() {
  /************************************************
   * Insert a long string, not working when
   *     packetSize = 4096
   * If
   *     packetSize = 16384
   * or higher, insertion works fine.
   *****************************************************/
  let s = '0123456789'.repeat(100000);
  request = new Request("Insert into dbo.Owner VALUES ('Rick', '" + s + "')", function(err, rowCount) {
    if (err) {
      console.log(err);
    } else {
      console.log(rowCount + ' rows');
    }
  });

  connection.execSql(request);
}
released

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

κΈ΄ 쿼리λ₯Ό μ‹€ν–‰ν•  λ•Œ Connection lost - read ECONNRESET λ₯Ό λ°›μ•˜μŠ΅λ‹ˆλ‹€. encrypt: true 및 packetSize: 32768 ν•˜λ©΄ λͺ¨λ“  것이 잘 μž‘λ™ν•©λ‹ˆλ‹€.

λ…Έλ“œ 버전: v12.6.0

λͺ¨λ“  9 λŒ“κΈ€

λΉ„μŠ·ν•œ λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€. κΈ΄ λ¬Έμžμ—΄μ„ μ‚½μž…ν•˜λ €κ³  ν•  λ•Œ. μ•½κ°„μ˜ ν…ŒμŠ€νŠΈ 후에 우리의 경우 dockerized 된 μ‚¬μš© 된 nodejs 버전과 관련이 있음이 λ°ν˜€μ‘ŒμŠ΅λ‹ˆλ‹€.
node:10-slim -> 잘 μž‘λ™ν•©λ‹ˆλ‹€.
λ…Έλ“œ:12.3.1 -> 잘 μž‘λ™ν•©λ‹ˆλ‹€.
node:12.4 λ₯Ό μ‹œμž‘ν•˜λ©΄ μ†ŒμΌ“ 쀑단 λ˜λŠ” μ†ŒμΌ“ λ‹«νž˜ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš” @ricklang , μ €λŠ” 이것을 μ°Ύκ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€. "encrypt: true"κ°€ ν•„μˆ˜ μ„€μ •μž…λ‹ˆκΉŒ? 그렇지 μ•Šμ€ 경우 false둜 μ„€μ •ν•˜κ±°λ‚˜ κΈ°λ³Έκ°’ -falseλ₯Ό μ‚¬μš©ν•˜μ—¬ μ΄λŸ¬ν•œ 문제λ₯Ό ν•΄κ²°ν•  μˆ˜λ„ μžˆλŠ” μ˜΅μ…˜μ—μ„œ μ„€μ •ν•˜μ§€ λ§ˆμ‹­μ‹œμ˜€. μ™œ 이런 일이 λ°œμƒν•˜λŠ”μ§€ μ•Œμ•„ λ‚΄λ €κ³  λ…Έλ ₯ν–ˆμ§€λ§Œ μ΄κ²ƒμ˜ κ·Όλ³Έ 원인을 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. μ•”ν˜Έν™” μ—°κ²°κ³Ό λΉ„μ•”ν˜Έν™” μ—°κ²° λͺ¨λ‘μ— λŒ€ν•΄ νŒ¨ν‚·μ„ ν™•μΈν–ˆλŠ”λ° νŒ¨ν‚·μ΄ μ •ν™•νžˆ λ™μΌν•˜μ§€λ§Œ ν•˜λ‚˜λ₯Ό μ•”ν˜Έν™”ν•˜λŠ” 경우 EOM이 μžˆλŠ” λ§ˆμ§€λ§‰ νŒ¨ν‚·μ„ μˆ˜μ‹ ν•  λ•Œ μ—°κ²° λŠκΉ€ 였λ₯˜κ°€ μˆ˜μ‹ λ©λ‹ˆλ‹€. 쑰금 더 쑰사해 λ³΄κ² μŠ΅λ‹ˆλ‹€. νŒŒν—€μΉ  수 μžˆλŠ” 것이 μžˆλŠ”μ§€ ν™•μΈν•˜κ² μŠ΅λ‹ˆλ‹€.
λ‹€λ₯Έ ν•œνŽΈμœΌλ‘œλŠ” 이에 λŒ€ν•΄ @arthurschreiber μ—κ²Œ λ¬Όμ–΄λ³Ό μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. κ·Έμ—κ²Œ 톡찰λ ₯이 μžˆλŠ”μ§€ ν™•μΈν•˜μ‹­μ‹œμ˜€.

와 ν•¨κ»˜

encrypt: false,

였λ₯˜ λ©”μ‹œμ§€λŠ” (νŒ¨ν‚· 크기에 관계없이):

RequestError: Requests can only be made in the LoggedIn state, not the SentPrelogin state
    at RequestError (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\errors.js:32:12)
    at Connection.makeRequest (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1680:24)
    at Connection.execSql (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1459:10)
    at executeInsert (C:\work\GitRepos\tedious-test\index.js:67:14)
    at Connection.<anonymous> (C:\work\GitRepos\tedious-test\index.js:24:5)
    at Connection.emit (events.js:200:13)
    at Connection.message (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1871:18)
    at Connection.dispatchEvent (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1172:36)
    at MessageIO.<anonymous> (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1045:14)
    at MessageIO.emit (events.js:200:13) {
  message: 'Requests can only be made in the ' +
    'LoggedIn state, not the SentPrelogin ' +
    'state',
  code: 'EINVALIDSTATE'

μ•”ν˜Έν™” 섀정을 μ œκ±°ν•˜κ³  νŒ¨ν‚· 크기λ₯Ό 4096으둜 두면 였λ₯˜ λ©”μ‹œμ§€λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

ConnectionError: Connection lost - write ECONNRESET
    at ConnectionError (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\errors.js:13:12)
    at Connection.socketError (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1187:26)
    at Socket.<anonymous> (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1032:14)
    at Socket.emit (events.js:205:15)
    at errorOrDestroy (internal/streams/destroy.js:107:12)
    at onwriteError (_stream_writable.js:438:5)
    at onwrite (_stream_writable.js:459:5)
    at internal/streams/destroy.js:49:7
    at Socket._destroy (net.js:593:3)
    at Socket.destroy (internal/streams/destroy.js:37:8)
Emitted 'error' event at:
    at Connection.socketError (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1187:12)
    at Socket.<anonymous> (C:\work\GitRepos\tedious-test\node_modules\tedious\lib\connection.js:1032:14)
    [... lines matching original stack trace ...]
    at Socket.destroy (internal/streams/destroy.js:37:8)
    at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:84:12) {
  message: 'Connection lost - write ECONNRESET',
  code: 'ESOCKET'

κ·ΈλŸ¬λ‚˜ μ•”ν˜Έν™”λ₯Ό μ„€μ •ν•˜μ§€ μ•Šκ³  νŒ¨ν‚· 크기λ₯Ό 16384둜 늘리면 λͺ¨λ“  것이 μ œλŒ€λ‘œ μž‘λ™ν•©λ‹ˆλ‹€.

그건 κ·Έλ ‡κ³ , λ‚˜λŠ” λ…Έλ“œ 버전을 ν…ŒμŠ€νŠΈν–ˆμŠ΅λ‹ˆλ‹€: 12.4.0, 12.6.0. 같은 κ²°κ³Όμž…λ‹ˆλ‹€.

κΈ΄ 쿼리λ₯Ό μ‹€ν–‰ν•  λ•Œ Connection lost - read ECONNRESET λ₯Ό λ°›μ•˜μŠ΅λ‹ˆλ‹€. encrypt: true 및 packetSize: 32768 ν•˜λ©΄ λͺ¨λ“  것이 잘 μž‘λ™ν•©λ‹ˆλ‹€.

λ…Έλ“œ 버전: v12.6.0

@ wy193777 μΆ”κ°€ μ˜΅μ…˜ 없이 μ΅œλŒ€ 12.3.1μ—μ„œ λ…Έλ“œ 버전을 μ‚¬μš©ν•˜μ—¬ λͺ¨λ“  것이 μž‘λ™ν•˜λŠ”μ§€ 확인할 수 μžˆμŠ΅λ‹ˆκΉŒ?

@susares λ…Έλ“œ v12.3.1은 packetSize μ˜΅μ…˜ 없이 μž‘λ™ν•©λ‹ˆλ‹€.

λ…Έλ“œ 버전: v12.2.0은 packetSize μ˜΅μ…˜ 없이 μž‘λ™ν•©λ‹ˆλ‹€.
λ…Έλ“œ 버전: v.12.6.0μ—μ„œ Connection lost - read ECONNRESET 였λ₯˜λ₯Ό ν”Όν•˜κΈ° μœ„ν•΄ packetSize: 8192 λ₯Ό μ‚¬μš©ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€.

이것은 https://github.com/nodejs/node/pull/27861 λ•Œλ¬ΈμΈ 것 κ°™μŠ΅λ‹ˆλ‹€. μ–΄μ¨Œλ“  큰 TLS μ„Έκ·Έλ¨ΌνŠΈκ°€ μž‘μ„±λ˜λ©΄ SQLServerκ°€ 연결을 μ’…λ£Œν•©λ‹ˆλ‹€. λ‚˜λŠ” μˆ˜μ • 사항이 있으며 곧 PR을 μ—΄ κ²ƒμž…λ‹ˆλ‹€. πŸ‘

기닀릴 수 μ—†λŠ” μ‚¬λžŒλ“€μ„ μœ„ν•΄ 이 문제λ₯Ό ν•΄κ²°ν•  diffκ°€ μžˆμŠ΅λ‹ˆλ‹€.

diff --git a/src/message-io.js b/src/message-io.js
index 90875f8..79f5da8 100644
--- a/src/message-io.js
+++ b/src/message-io.js
@@ -72,6 +72,8 @@ module.exports = class MessageIO extends EventEmitter {
       encrypted: duplexpair.socket2
     };

+    securePair.cleartext.setMaxSendFragment(this.outgoingMessageStream.packetSize);
+
     // If an error happens in the TLS layer, there is nothing we can do about it.
     // Forward the error to the socket so the connection gets properly cleaned up.
     securePair.cleartext.on('error', (err) => {

:tada: 이 λ¬Έμ œλŠ” 버전 6.2.1μ—μ„œ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

λ¦΄λ¦¬μŠ€λŠ” λ‹€μŒμ—μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ‹œλ§¨ν‹± 릴리슀 봇 :package::rocket:

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰