消息:读取ECONNRESET,堆栈:错误:从Docker容器内的Go客户端调用HapiJs服务器时读取ECONNRESET

  • Node Version: 6.11.1
  • Platform: Ubuntu 14.04 inside a docker container.
  • Subsystem: http

A very unique problem faced when calling an endpoint in a Node project running a hapijs server. When the endpoint is hit directly, there aren't any problems.

But when we hit it from a gohaqd instance, we get:

170809/044343.745, [log,connection,client,error] message: write EPIPE, stack: Error: write EPIPE at exports._errnoException (util.js:1018:11) at WriteWrap.afterWrite (net.js:800:14)

and more often

170809/040643.248, [log,connection,client,error] message: read ECONNRESET, stack: Error: read ECONNRESET at exports._errnoException (util.js:1018:11) at TCP.onread (net.js:568:26)

I know the error codes mean that somewhere, the app is trying to write to a closed connection. But for the life of me I can't figure out where. The logs themselves are from hapijs, this line if I'm not wrong, but couldn't figure out why node was trying to write to a closed connection, anyway.

Mind, there's no side-effect from this. The app runs fine :|

We turned on NODE_DEBUG=http, net and got the following results. The only thing that stuck out when reading these is that in the second the write ret = true line appears twice, if that means anything. Can someone help me understand what it means?

The first one is when hitting the endpoint directly:

NET 422: onconnection
NET 422: _read
NET 422: Socket._read readStart
HTTP 422: SERVER new http connection
HTTP 422: SERVER socketOnParserExecute 333
NET 422: onread 775
NET 422: got data
NET 422: _read
HTTP 422: call onSocket 0 0
HTTP 422: createConnection api.mixpanel.com:80: { servername: 'api.mixpanel.com',
  path: null,
  headers: {},
  port: 80,
  host: 'api.mixpanel.com',
  _agentKey: 'api.mixpanel.com:80:' }
NET 422: createConnection [ { servername: 'api.mixpanel.com',
    path: null,
    headers: {},
    port: 80,
    host: 'api.mixpanel.com',
    _agentKey: 'api.mixpanel.com:80:',
    encoding: null },
  [Function: oncreate] ]
NET 422: pipe false null
NET 422: connect: find host api.mixpanel.com
NET 422: connect: dns options { family: undefined, hints: 32 }
HTTP 422: sockets api.mixpanel.com:80: 1
HTTP 422: outgoing message end.
HTTP 422: call onSocket 1 0
HTTP 422: createConnection api.mixpanel.com:80: { servername: 'api.mixpanel.com',
  path: null,
  headers: {},
  port: 80,
  host: 'api.mixpanel.com',
  _agentKey: 'api.mixpanel.com:80:' }
NET 422: createConnection [ { servername: 'api.mixpanel.com',
    path: null,
    headers: {},
    port: 80,
    host: 'api.mixpanel.com',
    _agentKey: 'api.mixpanel.com:80:',
    encoding: null },
  [Function: oncreate] ]
NET 422: pipe false null
NET 422: connect: find host api.mixpanel.com
NET 422: connect: dns options { family: undefined, hints: 32 }
HTTP 422: sockets api.mixpanel.com:80: 2
HTTP 422: outgoing message end.
HTTP 422: call onSocket 2 0
HTTP 422: createConnection api.mixpanel.com:80: { servername: 'api.mixpanel.com',
  path: null,
  headers: {},
  port: 80,
  host: 'api.mixpanel.com',
  _agentKey: 'api.mixpanel.com:80:' }
NET 422: createConnection [ { servername: 'api.mixpanel.com',
    path: null,
    headers: {},
    port: 80,
    host: 'api.mixpanel.com',
    _agentKey: 'api.mixpanel.com:80:',
    encoding: null },
  [Function: oncreate] ]
NET 422: pipe false null
NET 422: connect: find host api.mixpanel.com
NET 422: connect: dns options { family: undefined, hints: 32 }
HTTP 422: sockets api.mixpanel.com:80: 3
HTTP 422: outgoing message end.
NET 422: _read
NET 422: _read wait for connection
NET 422: _read
NET 422: _read wait for connection
NET 422: _read
NET 422: _read wait for connection
NET 422: afterConnect
NET 422: _read
NET 422: Socket._read readStart
NET 422: afterConnect
NET 422: _read
NET 422: Socket._read readStart
NET 422: afterConnect
NET 422: _read
NET 422: Socket._read readStart
NET 422: onread 438
NET 422: got data
HTTP 422: AGENT incoming response!
HTTP 422: AGENT isHeadResponse false
NET 422: _read
HTTP 422: AGENT socket.destroySoon()
NET 422: onSocketFinish
NET 422: oSF: not ended, call shutdown()
NET 422: destroy undefined
NET 422: destroy
NET 422: close
NET 422: close handle
NET 422: afterShutdown destroyed=true ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: false,
  endEmitted: false,
  reading: true,
  sync: false,
  needReadable: true,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: emit close
HTTP 422: CLIENT socket onClose
HTTP 422: removeSocket api.mixpanel.com:80: writable: false
HTTP 422: HTTP socket close
NET 422: onread 438
NET 422: got data
HTTP 422: AGENT incoming response!
HTTP 422: AGENT isHeadResponse false
NET 422: _read
HTTP 422: AGENT socket.destroySoon()
NET 422: onSocketFinish
NET 422: oSF: not ended, call shutdown()
NET 422: destroy undefined
NET 422: destroy
NET 422: close
NET 422: close handle
NET 422: onread 486
NET 422: got data
HTTP 422: AGENT incoming response!
HTTP 422: AGENT isHeadResponse false
NET 422: _read
HTTP 422: AGENT socket.destroySoon()
NET 422: onSocketFinish
NET 422: oSF: not ended, call shutdown()
NET 422: destroy undefined
NET 422: destroy
NET 422: close
NET 422: close handle
NET 422: afterShutdown destroyed=true ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: false,
  endEmitted: false,
  reading: true,
  sync: false,
  needReadable: true,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: emit close
HTTP 422: CLIENT socket onClose
HTTP 422: removeSocket api.mixpanel.com:80: writable: false
HTTP 422: HTTP socket close
NET 422: afterShutdown destroyed=true ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: false,
  endEmitted: false,
  reading: true,
  sync: false,
  needReadable: true,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: emit close
HTTP 422: CLIENT socket onClose
HTTP 422: removeSocket api.mixpanel.com:80: writable: false
HTTP 422: HTTP socket close
HTTP 422: write ret = true
HTTP 422: outgoing message end.
NET 422: onread -4095
NET 422: EOF
NET 422: onSocketEnd ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: true,
  endEmitted: false,
  reading: false,
  sync: false,
  needReadable: false,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: onSocketFinish
NET 422: oSF: ended, destroy ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: true,
  endEmitted: true,
  reading: false,
  sync: false,
  needReadable: false,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: destroy undefined
NET 422: destroy
NET 422: close
NET 422: close handle
NET 422: has server
NET 422: SERVER _emitCloseIfDrained
NET 422: SERVER handle? true   connections? 15
NET 422: emit close
HTTP 422: server socket close

The next one is when the endpoint is hit from gohaqd, which is a go client.

NET 422: onread 405
NET 422: got data
NET 422: _read
NET 422: onconnection
NET 422: _read
NET 422: Socket._read readStart
HTTP 422: SERVER new http connection
HTTP 422: SERVER socketOnParserExecute 325
NET 422: onread 775
NET 422: got data
NET 422: _read
HTTP 422: call onSocket 0 0
HTTP 422: createConnection api.mixpanel.com:80: { servername: 'api.mixpanel.com',
  path: null,
  headers: {},
  port: 80,
  host: 'api.mixpanel.com',
  _agentKey: 'api.mixpanel.com:80:' }
NET 422: createConnection [ { servername: 'api.mixpanel.com',
    path: null,
    headers: {},
    port: 80,
    host: 'api.mixpanel.com',
    _agentKey: 'api.mixpanel.com:80:',
    encoding: null },
  [Function: oncreate] ]
NET 422: pipe false null
NET 422: connect: find host api.mixpanel.com
NET 422: connect: dns options { family: undefined, hints: 32 }
HTTP 422: sockets api.mixpanel.com:80: 1
HTTP 422: outgoing message end.
HTTP 422: call onSocket 1 0
HTTP 422: createConnection api.mixpanel.com:80: { servername: 'api.mixpanel.com',
  path: null,
  headers: {},
  port: 80,
  host: 'api.mixpanel.com',
  _agentKey: 'api.mixpanel.com:80:' }
NET 422: createConnection [ { servername: 'api.mixpanel.com',
    path: null,
    headers: {},
    port: 80,
    host: 'api.mixpanel.com',
    _agentKey: 'api.mixpanel.com:80:',
    encoding: null },
  [Function: oncreate] ]
NET 422: pipe false null
NET 422: connect: find host api.mixpanel.com
NET 422: connect: dns options { family: undefined, hints: 32 }
HTTP 422: sockets api.mixpanel.com:80: 2
HTTP 422: outgoing message end.
HTTP 422: call onSocket 2 0
HTTP 422: createConnection api.mixpanel.com:80: { servername: 'api.mixpanel.com',
  path: null,
  headers: {},
  port: 80,
  host: 'api.mixpanel.com',
  _agentKey: 'api.mixpanel.com:80:' }
NET 422: createConnection [ { servername: 'api.mixpanel.com',
    path: null,
    headers: {},
    port: 80,
    host: 'api.mixpanel.com',
    _agentKey: 'api.mixpanel.com:80:',
    encoding: null },
  [Function: oncreate] ]
NET 422: pipe false null
NET 422: connect: find host api.mixpanel.com
NET 422: connect: dns options { family: undefined, hints: 32 }
HTTP 422: sockets api.mixpanel.com:80: 3
HTTP 422: outgoing message end.
NET 422: _read
NET 422: _read wait for connection
NET 422: _read
NET 422: _read wait for connection
NET 422: _read
NET 422: _read wait for connection
NET 422: afterConnect
NET 422: _read
NET 422: Socket._read readStart
NET 422: afterConnect
NET 422: _read
NET 422: Socket._read readStart
NET 422: afterConnect
NET 422: _read
NET 422: Socket._read readStart
NET 422: onread 438
NET 422: got data
HTTP 422: AGENT incoming response!
HTTP 422: AGENT isHeadResponse false
NET 422: _read
HTTP 422: AGENT socket.destroySoon()
NET 422: onSocketFinish
NET 422: oSF: not ended, call shutdown()
NET 422: destroy undefined
NET 422: destroy
NET 422: close
NET 422: close handle
NET 422: afterShutdown destroyed=true ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: false,
  endEmitted: false,
  reading: true,
  sync: false,
  needReadable: true,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: emit close
HTTP 422: CLIENT socket onClose
HTTP 422: removeSocket api.mixpanel.com:80: writable: false
HTTP 422: HTTP socket close
NET 422: onread 438
NET 422: got data
HTTP 422: AGENT incoming response!
HTTP 422: AGENT isHeadResponse false
NET 422: _read
HTTP 422: AGENT socket.destroySoon()
NET 422: onSocketFinish
NET 422: oSF: not ended, call shutdown()
NET 422: destroy undefined
NET 422: destroy
NET 422: close
NET 422: close handle
NET 422: onread 486
NET 422: got data
HTTP 422: AGENT incoming response!
HTTP 422: AGENT isHeadResponse false
NET 422: _read
HTTP 422: AGENT socket.destroySoon()
NET 422: onSocketFinish
NET 422: oSF: not ended, call shutdown()
NET 422: destroy undefined
NET 422: destroy
NET 422: close
NET 422: close handle
NET 422: afterShutdown destroyed=true ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: false,
  endEmitted: false,
  reading: true,
  sync: false,
  needReadable: true,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: emit close
HTTP 422: CLIENT socket onClose
HTTP 422: removeSocket api.mixpanel.com:80: writable: false
HTTP 422: HTTP socket close
NET 422: afterShutdown destroyed=true ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: false,
  endEmitted: false,
  reading: true,
  sync: false,
  needReadable: true,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: emit close
HTTP 422: CLIENT socket onClose
HTTP 422: removeSocket api.mixpanel.com:80: writable: false
HTTP 422: HTTP socket close
HTTP 422: write ret = true
NET 422: afterWrite 0
NET 422: afterWrite call cb
HTTP 422: write ret = true
HTTP 422: outgoing message end.
NET 422: onread -4095
NET 422: EOF
NET 422: onSocketEnd ReadableState {
  objectMode: false,
  highWaterMark: 16384,
  buffer: BufferList { head: null, tail: null, length: 0 },
  length: 0,
  pipes: null,
  pipesCount: 0,
  flowing: true,
  ended: true,
  endEmitted: false,
  reading: false,
  sync: false,
  needReadable: false,
  emittedReadable: false,
  readableListening: false,
  resumeScheduled: false,
  defaultEncoding: 'utf8',
  ranOut: false,
  awaitDrain: 0,
  readingMore: false,
  decoder: null,
  encoding: null }
NET 422: afterWrite 0
NET 422: afterWrite call cb
NET 422: afterWrite -32
NET 422: write failure { Error: write EPIPE
    at exports._errnoException (util.js:1018:11)
    at WriteWrap.afterWrite (net.js:800:14) code: 'EPIPE', errno: 'EPIPE', syscall: 'write' }
NET 422: destroy
NET 422: close
NET 422: close handle
170809/101228.947, [log,connection,client,error] message: write EPIPE, stack: Error: write EPIPE
    at exports._errnoException (util.js:1018:11)
    at WriteWrap.afterWrite (net.js:800:14)
NET 422: has server
NET 422: SERVER _emitCloseIfDrained
NET 422: SERVER handle? true   connections? 15
NET 422: emit close
HTTP 422: server socket close

The go code that calls this:

// Sends a POST request to consumption endpoint with the SQS message as body
func sendMessageToURL(msg string) bool {
    var resp *http.Response
    var err error

    endpoint := url

    if endpoint == "" {
        m := make(map[string]string)
        err := json.Unmarshal([]byte(msg), &m)
        if err != nil {
            log.Printf("Unable to parse JSON message to get the URL: %s", msg)
            return false
        }
        endpoint = m["url"]
        if endpoint == "" {
            log.Printf("No 'url' field found in JSON message: %s", msg)
            return false
        }
    }

    for {
        resp, err = httpClient.Post(endpoint, "application/json", bytes.NewBuffer([]byte(msg)))
        if err == nil {
            break
        }
        log.Printf("Error hitting endpoint, retrying after 1 second... Error: %s", err.Error())
        time.Sleep(time.Second)
    }
    defer resp.Body.Close()

    // return true only if response is 200 OK
    if resp.StatusCode != 200 {
        bodyBytes, _ := ioutil.ReadAll(resp.Body)
        log.Printf("Error: Non OK response: %s Status Code: '%s' for sent message: '%s'", string(bodyBytes), resp.Status, msg)
        return false
    }

    return true
}