Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node v20, closing server and re-listening between requests causes ECONNRESET #1776

Open
isaacs opened this issue Sep 10, 2023 · 3 comments
Open
Labels

Comments

@isaacs
Copy link

isaacs commented Sep 10, 2023

Repeating a request to a server after it's been closed and re-opened seems to try to re-use the prior connection, resulting in ECONNRESET.

Reproduction

Steps to reproduce the behavior:

Using node 20.6.1

// test.mjs
import { createServer } from 'node:http'
import fetch from 'node-fetch'

const server = createServer((req, res) => {
  res.writeHead(200, {
    // connection: 'close',
    'content-type': 'application/json',
  })
  res.end(
    JSON.stringify({
      hello: req.url === '/' ? 'world' : String(req.url).slice(1),
    })
  )
})

server.listen({ host: '127.0.0.1', port: 65200 })

{
  const res = await fetch('http://127.0.0.1:65200/')
  console.error(res.status, res.headers)
  console.log(await res.text())
}

server.close()
server.listen({ host: '127.0.0.1', port: 65200 })

{
  const res = await fetch('http://127.0.0.1:65200/')
  console.error(res.status, res.headers)
  console.log(await res.text())
}

server.close()

Expected behavior

Connection is closed, so it is not re-used.

Screenshots

Your Environment

software version
node-fetch 3.3.2
node 20.6.1
npm 10.0.0
Operating System Darwin moxy.lan 22.6.0 Darwin Kernel Version 22.6.0: Wed Jul 5 22:22:05 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T6000 arm64

Additional context

Worked fine in node 18. I haven't dug into what might have changed, but perhaps the connection close isn't being surfaced in the same way?

Node's built-in http.request() works in this scenario without any problem.

@isaacs isaacs added the bug label Sep 10, 2023
@zalox
Copy link

zalox commented Sep 16, 2023

I also encountered this bug now when attempting to do consecutive calls to an API. One workaround I found was to include a await new Promise(resolve => resolve(setTimeout)); before the await fetch. So there is probably a synchronization bug somewhere.

The same code base works as expected with node 18, so I switched to that for now.

@Moumouls
Copy link

Moumouls commented Sep 22, 2023

My team encountered the same issue. In our test suite for impacted test we provided a new agent without keep alive.

Btw, think it's not really an issue of node-fetch, but a new behavior of Node 19 and 20. Since Node 19 the global default agent use keep alive.

The workaround is providing a custom agent for impacted test calls.

import { Agent } from 'http'
import fetch from 'node-fetch'

fetch(myUrl, { agent: new Agent() })

Technically this kind of issue should only occur in test purpose. Another solution is to change the port between each test.

@isaacs
Copy link
Author

isaacs commented Sep 30, 2023

Technically this kind of issue should only occur in test purpose. Another solution is to change the port between each test.

If you make repeated requests to a server in production, and the connection closes between requests, it could happen in production as well. Servers do restart sometimes in real life.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants