netlify / cli

Netlify Command Line Interface
http://cli.netlify.com
MIT License
1.58k stars 352 forks source link

Function with serverless app crashes after second request running in `netlify dev` #6840

Open rlmcneary2 opened 3 weeks ago

rlmcneary2 commented 3 weeks ago

Describe the bug

I have a function named "index" that uses serverless to return a Koa app. The function builds successfully and starts using dev. If I make requests against the root endpoint using a tool like postman, the cli will crash after the second request completes. It crashes in the browser too but it's easier to see the behavior in a tool that makes a single request.

Steps to reproduce

  1. git clone https://codeberg.org/rlmcneary2/funcstache-website.git
  2. Switch to branch "cli-crash"
  3. npm i
  4. npm run build && npm run dev
  5. Open a tool like postman or rested and send a request to "http://localhost:8888/"
  6. Send the request again.

Following the second request others will fail because the cli process has exited.

◈ Rewrote URL to /.netlify/functions/index/
Request from 127.0.0.1: GET /.netlify/functions/index/
--- index: ENTER[catcher] status=404
--- index: ENTER[funcstache] status=404
funcstache(middleware): url='/'
funcstache(middleware): requestedUrl='site/'
--- index: koa app started; http://localhost:3000
getTemplatePartials: source template='layout', add to pending: { sourceTemplateDir: '', templateFilename: '', templateName: 'main' }
getTemplatePartials: source template='layout', add to pending: {
  sourceTemplateDir: './layouts/default',
  templateFilename: '../../shared/nav/nav',
  templateName: 'navItems'
}
readTemplateFile: templateName='navItems', sourceTemplateDir='./layouts/default'
readTemplateFile: templateName='main', sourceTemplateDir=''
readTemplateFile: templateName='layout', sourceTemplateDir=''
funcstache(middleware): url='/'; exit
--- index: EXIT[funcstache] status=200
--- index: EXIT[catcher] status=200
Response with status 200 in 68 ms.
◈ Rewrote URL to /.netlify/functions/index/
Request from 127.0.0.1: GET /.netlify/functions/index/
--- index: ENTER[catcher] status=404
--- index: ENTER[funcstache] status=404
funcstache(middleware): url='/'
funcstache(middleware): requestedUrl='site/'

 ›   Error: Netlify CLI has terminated unexpectedly
This is a problem with the Netlify CLI, not with your application.
If you recently updated the CLI, consider reverting to an older version by running:

npm install -g netlify-cli@VERSION
You can use any version from https://ntl.fyi/cli-versions.
Please report this problem at https://ntl.fyi/cli-error including the error details below.

getTemplatePartials: source template='layout', add to pending: { sourceTemplateDir: '', templateFilename: '', templateName: 'main' }
getTemplatePartials: source template='layout', add to pending: {
  sourceTemplateDir: './layouts/default',
  templateFilename: '../../shared/nav/nav',
  templateName: 'navItems'
}
readTemplateFile: templateName='navItems', sourceTemplateDir='./layouts/default'
readTemplateFile: templateName='main', sourceTemplateDir=''
readTemplateFile: templateName='layout', sourceTemplateDir=''
funcstache(middleware): url='/'; exit
--- index: EXIT[funcstache] status=200
--- index: EXIT[catcher] status=200
Response with status 200 in 42 ms.
Error: listen EADDRINUSE: address already in use 127.0.0.1:3000
    at Server.setupListenHandle [as _listen2] (node:net:1904:16)
    at listenInCluster (node:net:1961:12)
    at GetAddrInfoReqWrap.doListen (node:net:2135:7)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:111:8)

  System:
    OS: Linux 5.15 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish)
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
  Binaries:
    Node: 20.16.0 - ~/.nvm/versions/node/v20.16.0/bin/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 10.8.1 - ~/.nvm/versions/node/v20.16.0/bin/npm
  Browsers:
    Chrome: 113.0.5672.63

Requests against the "images" function in the environment (a standard synchronous function) never fail.

Configuration

[build] environment = { NODE_VERSION = "20.16.0" }

[dev] autoLaunch = false

[context.dev] publish = "."

[functions."images"] included_files = ["./images/**"]

[functions."index"] included_files = ["./site/**"]

[[redirects]] force = true from = "/favicon.ico" status = 200 to = "/images/favicon.ico"

[[redirects]] force = true from = "/images/*" status = 200 to = "/.netlify/functions/images/:splat"

[[redirects]] force = true from = "/*" status = 200 to = "/.netlify/functions/index/:splat"

Environment

Ubuntu running in WSL2.

System: OS: Linux 5.15 Ubuntu 22.04.3 LTS 22.04.3 LTS (Jammy Jellyfish) CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz Memory: 4.96 GB / 7.61 GB Container: Yes Shell: 5.8.1 - /usr/bin/zsh Binaries: Node: 20.16.0 - ~/.nvm/versions/node/v20.16.0/bin/node Yarn: 1.22.19 - /usr/bin/yarn npm: 10.8.1 - ~/.nvm/versions/node/v20.16.0/bin/npm npmPackages: netlify-cli: ^17.36.2 => 17.36.2

tlane25 commented 5 days ago

Hey @rlmcneary2!

I looked into this bug with @wconrad265 today and I think we understand the issue on a high level. When we ran netlify dev on a local instance of your repo, we were able to replicate the issue (first ping to the server successful, the second unsuccessful due to port already in use). Everytime a request hits the server, the createApp() function initializes app to listen on port 3000. Thus, first time works, but at the time of second request port 3000 is taken.

function createApp() {
  const app = new koa();
  app
    .use(
      logAround("catcher", async (ctx, next) => {
        try {
          await next();
        } catch (err) {
          console.error("main: err=", err);
          ctx.status = 500;
          ctx.body = err.message || JSON.stringify(err);
        }
      })
    )
    .use(logAround("funcstache", funcstache(SITE_PATH)));

  app.listen(port, host, () => {
    console.log(`--- index: koa app started; http://${host}:${port}`);
  });

  return app;
}

We deployed your site into production and did not see the same issue. We believe this is because every time a request is sent in the production environment, a new, unrelated serverless function is created in the cloud.

We're looking into how serverless functions are deployed with netlify dev to find a solution!

wconrad265 commented 5 days ago

To add to @tlane25 analysis, I wanted to add some pictures to help illustrate the point above.

Before starting the application, as we can see port 3000 is not in use.

image

After starting the application, with netlify dev. We have not visited the server yet. As we can see port 3000 is not in use just yet.

image

When we visit http://localhost:8888, we can see the server has now run and the request/response process has been completed. However, the port 3000 that the server-less function opens, is still open. This leads to our error below.

image

Because port 3000 is still open, when we revisit the website, the serverless function throws an error. This is because the port is in use.

image