skip to Main Content

I am using SvelteKit, Vite.js, and the mariadb package with Node.js in my application. I have the following code in the db.js file:

import mariadb from 'mariadb';

const databaseConnectionPoolConfig = {
  ...
};

let databaseConnectionPool = undefined;

export function createDatabaseConnectionPool() {
  return databaseConnectionPool ??= mariadb.createPool(databaseConnectionPoolConfig);
}

Inside the hooks.server.js file, I have the following code:

import { createDatabaseConnectionPool } from '$lib/db';

createDatabaseConnectionPool();

When a hot reload is performed, the databaseConnectionPool is reset to undefined, but the connections in the pool are not closed, and new ones are created. I checked this by running the following query:

SHOW STATUS LIKE 'Threads_connected';

Which increases each time a hot reload is performed by the number of connections specified by the databaseConnectionPoolConfig.connectionLimit property.

How can I prevent this from happening?

2

Answers


  1. I’m looking for a clear, step-by-step solution to maintain a database connection pool while performing a hot reload in SvelteKit with Vite.js and MariaDB.

    Currently, the problem is that the connection pool is reset to undefined with each hot reload, resulting in new connections.

    You would need to implement a mechanism to persist the database connection pool across hot reloads.

    In the context of hot module reloading (HMR) with Vite.js, Node.js global variables are usually not preserved. That is because the server-side code gets re-executed, resetting the state of these variables.

    Hot module reloading replaces the modified modules without restarting the server, which means the global scope in each module would get reset. However, Node.js built-in modules and their state, like require.cache, may not necessarily be cleared upon HMR, and this behavior could potentially be leveraged to preserve certain data like a database connection pool.

    Modify your db.js to store the database connection pool in require.cache if it does not already exist:

    import mariadb from 'mariadb';
    
    const databaseConnectionPoolConfig = {
      // your existing config here
    };
    
    function createDatabaseConnectionPool() {
      const cacheKey = require.resolve(__filename); // Unique identifier for this module.
      const cached = require.cache[cacheKey];
    
      // If a cached pool exists, return that.
      if (cached && cached.exports && cached.exports.databaseConnectionPool) {
        return cached.exports.databaseConnectionPool;
      }
    
      const databaseConnectionPool = mariadb.createPool(databaseConnectionPoolConfig);
    
      // Cache the database pool for future use.
      if (cached && cached.exports) {
        cached.exports.databaseConnectionPool = databaseConnectionPool;
      }
    
      return databaseConnectionPool;
    }
    
    export { createDatabaseConnectionPool };
    

    Then:

    • Run your SvelteKit application.
    • Perform a hot reload by modifying some code.
    • Run the SQL query SHOW STATUS LIKE 'Threads_connected'; again to check if the number of threads connected increases or not.

    By doing this, you should be able to maintain the same database connection pool even after multiple hot reloads, provided your development environment does not clear require.cache on a hot reload.

    Login or Signup to reply.
  2. In the code provided, each time the hot module replacement (HMR) is triggered, the module is re-evaluated. Based on that code this leads to a new pool of connections getting created without closing the existing pool of connections.

    To prevent the above, the code can be modified to check for an existing pool, close it and then create a new pool.

    Also, it would be wise to make the function use await before calling the databaseConnectionPool.end() method since it is asynchronous and it needs to complete before proceeding, see amended function below:

    export async function createDatabaseConnectionPool() {
      // Check if the pool exists and close it
      if (databaseConnectionPool) {
        await databaseConnectionPool.end();
      }
    
      // Create a new pool and assign it to databaseConnectionPool
      databaseConnectionPool = mariadb.createPool(databaseConnectionPoolConfig);
      return databaseConnectionPool;
    }
    

    On the other hand it would be more efficient to actually reuse an existing data connection pool if it already exists, rather than wasting resources to recreate it each time. If that approach is more desirable, amend the function to the following:

    export function createDatabaseConnectionPool() {
      if (!databaseConnectionPool) {
        databaseConnectionPool = mariadb.createPool(databaseConnectionPoolConfig);
      }
      return databaseConnectionPool;
    }
    

    With this approach, the connection pool is initialised only once. Subsequent calls to createDatabaseConnectionPool will simply return the existing connection pool without creating a new one. This ensures the connection pool is reused and prevents the creation of a new connection pool with each HMR.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search