elysiajs / elysia-swagger

A plugin for Elysia to auto-generate Swagger page
MIT License
84 stars 45 forks source link

High Memory Usage (~100mb) #4

Closed patlux closed 1 year ago

patlux commented 1 year ago

Just want to note that adding this plugins adds ~100mb of memory usage:

CleanShot 2023-04-27 at 07 10 22 (Left: With Swagger Plugin, Right: Without Swagger Plugin)

CleanShot 2023-04-27 at 07 00 36

SaltyAom commented 1 year ago

May I ask some questions to help me investigate this further?

What is version of the following are you using:

And what OS are you running? (I assume running Linux, but just in case)

patlux commented 1 year ago

I just tested it again and it seems only to be this high, if every route is placed in one single file. In the meantime I splitted all of my routes into several files which fixed the high ram usage.

But here is a snippet to reproduce it:

import { bearer } from '@elysiajs/bearer'
import { swagger } from '@elysiajs/swagger'
import { memoryUsage } from 'bun:jsc'
import { Elysia, t } from 'elysia'

const humanFileSize = (size: number) => {
  const i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
  const a = parseFloat((size / Math.pow(1024, i)).toFixed(2))
  return a * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i]
}

setInterval(() => Bun.gc(true), 30_000)

setInterval(() => {
  const memory = memoryUsage()
  console.log(Object.entries(memory).map(([key, value]) => [key, humanFileSize(value)]))
}, 1000)

const logging = (app: Elysia) => {
  app.on('request', ({ request }) => {
    const uri = new URL(request.url)
    console.log(`>> [${request.method}] ${request.url.substring(uri.origin.length)}`)
  })
  return app
}

const app = new Elysia()
  // comment this out and see the output for comparing the ram usage
  .use(
    swagger({
      exclude: [/^\/admin/],
    })
  )
  .use(logging)
  .get('/health', () => {
    return 'OK'
  })
  .group('/admin', (app) =>
    app.use(bearer()).guard(
      {
        beforeHandle: ({ bearer }) => {},
      },
      (app) =>
        app
          .get('/clients', () => {
            return {}
          })
          .get('/users', () => {
            return {}
          })
          .get('/games', () => {
            return {}
          })
          .get('/user-sessions', () => {
            return {}
          })
          .post(
            '/sql',
            ({ body }) => {
              return ''
            },
            {
              schema: { body: t.String() },
            }
          )
    )
  )
  .get(
    '/app/game/:code',
    ({ params, query }) => {
      return ''
    },
    {
      schema: {
        params: t.Object({
          code: t.String(),
        }),
        query: t.Object({
          host: t.String(),
          owner: t.String(),
        }),
        response: {
          303: t.String(),
        },
      },
    }
  )
  .group('/auth', (app) =>
    app.use(bearer()).post(
      '/register-client',
      ({ body }) => {
        return ''
      },
      {
        beforeHandle: ({ bearer }) => {},
      }
    )
  )
  .group('/game', (app) =>
    app
      .get('', () => {
        return ''
      })
      .use(bearer())
      .derive(({ bearer }) => {
        return {}
      })
      .post('/', () => {
        return ''
      })
      .post('/join', async ({ query }) => {
        return ''
      })
      .group('/:gameId', (app) =>
        app
          .derive(() => {
            return {}
          })
          .get('/state', () => {
            return ''
          })
          .get('', async ({ query, request }) => {
            return ''
          })
          .post('', async ({ body }) => {
            return ''
          })
      )
  )
  .group('/users/:userId', (app) =>
    app
      .derive(({ params }) => {
        return {}
      })
      .get('', () => {
        return {}
      })
      .post('', ({}) => {
        return ''
      })
      .get('/games', () => {
        return ''
      })
  )
  .onError(({ error, code }) => {
    console.error({ error, code })

    if (code === 'VALIDATION') {
      console.log(error.all())
      return {
        code,
        message: `${error}`,
      }
    }

    return {
      error,
      code,
    }
  })
  .listen(4000, ({ hostname, port }) => {
    console.log(`Running at http://${hostname}:${port}`)
  })

export type App = typeof app
SaltyAom commented 1 year ago

Can you try updating @elysiajs/swagger to ^0.4.0.

The new version should use less memory.

patlux commented 1 year ago

@SaltyAom I can confirm, it uses now less memory. Instead of 150MB it's just 43MB at the start :) Thanks!