question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Node-API/`LibraryEngine`: `$disconnect` does not free up memory / kill engine

See original GitHub issue

When Node-API/engineType=library is active, calling $disconnect() does not free up the memory the instance of the Engine is using. This is because the engine is not killed as it is/was with the BinaryEngine (child process was completely killed on stop()), but only the disconnect is sent to the Engine. Then when another $connect or Query (which implicitly connects) comes in, the same instance of the QueryEngine is used again (vs. a newly started one, as with the binary).

If you (unrealistically) create many PrismaClient instances and just $disconnect them after use, this leads to growing memory usage until the script ends.

Context:

Reproduction above, running for 60 minutes:

  • Currently: 25467 rss 1605.77 MB
  • With library engine deleted on $disconnect: 43100 rss 288.34 MB

We think this is a problem, but not of highest priority and can be solved down the line.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:2
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
janpiocommented, Oct 6, 2021

Yes, that would be awesome. It might be related to the original problem I describe above, but is fundamentally a different area. If your reproduction helps understanding that problem in isolation, that would be amazing.

That cleanup code is pretty neat by the way - although a tiny bit scary. Good that you scoped it to the current user etc.

1reaction
haleksandrecommented, Oct 6, 2021

I found out that the connections goes into a “idle” state. Either $disconnect isn’t working properly or it is putting the connection in “idle” state.

I found a workaround to keep the connections down with a SQL script, which you either call within the middleware or teardown with the help of the $executeRawUnsafe function.

This is the SQL script:

WITH inactive_connections AS (
  SELECT
    pid,
    rank() over (partition by client_addr order by backend_start ASC) as rank
  FROM
    pg_stat_activity
  WHERE
    -- Exclude the thread owned connection (ie no auto-kill)
    pid <> pg_backend_pid( )
  AND
    -- Exclude known applications connections
    application_name !~ '(?:psql)|(?:pgAdmin.+)'
  AND
    -- Include connections to the same database the thread is connected to
    datname = current_database()
  AND
    -- Include connections using the same thread username connection
    usename = current_user
  AND
    -- Include inactive connections only
    state in ('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled')
  AND
    -- Include old connections (found with the state_change field)
    current_timestamp - state_change > interval '10 seconds'
)

SELECT
  pg_terminate_backend(pid)
FROM
  inactive_connections
WHERE
  rank > 1 -- Leave one connection for each application connected to the database;
// Teardown
await ctx.prisma.$executeRawUnsafe(`
  WITH inactive_connections AS (
    SELECT
      pid,
      rank() over (partition by client_addr order by backend_start ASC) as rank
    FROM
      pg_stat_activity
    WHERE
      -- Exclude the thread owned connection (ie no auto-kill)
      pid <> pg_backend_pid( )
    AND
      -- Exclude known applications connections
      application_name !~ '(?:psql)|(?:pgAdmin.+)'
    AND
      -- Include connections to the same database the thread is connected to
      datname = current_database()
    AND
      -- Include connections using the same thread username connection
      usename = current_user
    AND
      -- Include inactive connections only
      state in ('idle', 'idle in transaction', 'idle in transaction (aborted)', 'disabled')
    AND
      -- Include old connections (found with the state_change field)
      current_timestamp - state_change > interval '10 seconds'
  )

  SELECT
    pg_terminate_backend(pid)
  FROM
    inactive_connections
  WHERE
    rank > 1 -- Leave one connection for each application connected to the database;
`);

This cleans up all the “idle” connections that has been idling for 10 seconds or more.

Should I open another issue so someone could try to replicate & investigate to see if it is indeed a bug with $disconnect?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Memory leaks in Jest when running tests serially with `nApi ...
My understanding of Node-API and the query engine is very limited, ... $disconnect does not free up memory / kill engine #9044]) Do...
Read more >
Debugging Memory Leaks in Node.js Applications - Toptal
Memory leaks in long running Node.js applications are like ticking time bombs that, if left unchecked in production environments, can result in devastating ......
Read more >
Understanding Memory Leaks in Nodejs | by Chidume Nnamdi
A solution to this is to clear the timer with clearInterval API. This will free the aGlobaVar and can now be GC'd. If...
Read more >
FATAL ERROR: Ineffective mark-compacts near heap limit ...
The error occurs when you exceed the default maximum memory allowed for Node.js. All this does is increase the maximum memory allowed. Share....
Read more >
Errors | Node.js v19.3.0 Documentation
With few exceptions, Synchronous APIs (any blocking method that does not accept a ... library and some hooks for the JS engine are...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found