sveltejs / sapper

The next small thing in web development, powered by Svelte
https://sapper.svelte.dev
MIT License
7k stars 434 forks source link

Sapper & Socket.io CPU usage leak approaches 100% over a few weeks #1675

Closed ikaeon closed 3 years ago

ikaeon commented 3 years ago

I have put a few small personal sapper projects into AWS and noticed over time - around two weeks - the CPU increase usage of the node process running sapper is over 80% for sites that don't get any traffic.

To simplify things I used the quick-start demo and only created a socketo.io that only accepts connections in server.js:

  import sirv from 'sirv';
  import polka from 'polka';
  import compression from 'compression';
  import * as sapper from '@sapper/server';
  import sock from 'socket.io';

  const { PORT, NODE_ENV } = process.env;
  const dev = NODE_ENV === 'development';

  const {server} = polka() // You can also use Express
    .use(
        compression({ threshold: 0 }),
        sirv('static', { dev }),
        sapper.middleware()
    )
    .listen(PORT, err => {
        if (err) console.log('error', err);
    });

  sock(server).on('connection',(socket) => {
  });

and creates a connection in index.svelte:

  import successkid from 'images/successkid.jpg';
  import io from "socket.io-client";
  const socket = io();

https://github.com/ikaeon/sapper_hello

Even with this small changes there is a slight change in the CPU behavior of node. It is like some timers are not cleared and node jumps to the top of CPU usage then back down. As time goes on with greater frequency and greater CPU usage. Without socket.io included node sleeps, as one would expect if there are no connections.

Express instead of polka has the same issue. Strangely systemd-resolved also increases in CPU usage as well.

Sorry if this is not sapper issue, I am not a web dev, it could be a socket.io issue but Sapper/Svelte seems to performing the most code generation.

antony commented 3 years ago

Sapper doesn't really run a process, you're talking about Polka. Polka is the thing that is running in node. You've said above that the same issue happens with Express, so therefore the common factor here is SocketIO.

I would suggest therefore raising this with the SocketIO team, however, as we would require - they will want an isolated reproduction, and probably memory snapshots and such to show that it is actually SocketIO causing this leak. Without them, there isn't a huge amount we can do.

I might suggest creating a simple node http server and adding socketio into it, then running that in production for 2 weeks to reproduce.

ikaeon commented 3 years ago

Thanks antony. I think it might be related to Sappers server side rendering. I removed all traces of socket.io from the server.js but left socket.io in the index.svelte. I use strace to see if nodejs is sleeping while waiting for signal, it normally does and is expected behavior when no browsers are connected, but when socket.io() is in index.svelte nodejs doesn't sleep, something causes it to wake all the time.

So I moved socket.io() to onmount and now the nodejs is back to expected behavior of sleeping.

antony commented 3 years ago

It makes sense that socketio would keep the node process alive. It has to be alive for websockets to function.

ikaeon commented 3 years ago

Thanks antony,

If you don't mind me asking how do professionals know which functions/libraries not to include in an area that can be rendered server side. I assume the same things can happen in Next.js for example.

antony commented 3 years ago

I can't speak for professionals, but if you read the docs it tells you what runs on the server an what runs on the client. It's a lot harder in NextJS or Nuxt, because I've been there, and most people don't seem to know, so a lot of components just break in SSR and need excluding.

In sapper it's a few simple rules, unless I've forgotten some: