Rayrun
← Back to Discord Forum

can i have one database pool connection per worker ?

I see that no matter using globalSetup or beforeAll hook its not possible to maintain one database pool connection for all tests, am i correct or there is way around

This thread is trying to answer question "Is it possible to maintain one database pool connection for all tests?"

17 replies

can i have one database pool connection per worker ?

Create connection in worker scope fixture perhaps? https://playwright.dev/docs/test-fixtures#worker-scoped-fixtures

unfortunately, same behaviour its reconnecting everytime

I don't think it's playwright issue then

export default class DB {
  private pool: Pool;

  private DBConfig = {
    user: "db_user",
    host: "localhost",
    database: "dd",
    password: "dd",
    port: 5477, // Default PostgreSQL port is 5432
    max: 10, // Maximum number of connections in the pool
    idleTimeoutMillis: 30000, // Time a connection is kept idle before being closed
    connectionTimeoutMillis: 2000, // Time to wait for a new connection if all are busy
    allowExitOnIdle: false,
  };

  async getDBConnection(): Promise<Pool> {
    if (!this.pool) {
      this.pool = new Pool(this.DBConfig);
      console.log("\x1b[32m" + `---------> √ DB connection has been established! <---------`);
      return this.pool;
    } else {
      console.log("\x1b[32m" + `---------> √ DB connection is already established! <---------`);
      return this.pool;
    }

  }
}
dataBase: [ async ({}, use) => {
    const dataBase = new DB();
      await dataBase.getDBConnection();
      await use(dataBase);
    },
    { scope: 'worker' },
  ],
});

Thats weird the function is being executed twice

Screenshot_2023-08-03_at_16.13.58.png

maybe

dataBase: [ async ({}, use) => {
    const dataBase = new DB();
    const conn = await dataBase.getDBConnection();
    await use(conn)
  },
    { scope: 'worker' },
  ],
});

and try running with DEBUG=pw:test , maybe it will shed a light when why it triggers second time

First thing what is the problem attempting to be solved. Connection pooling is more a function for the database and client libraries to access the db. Depending on the database can be the DB routines may start services and connection pooling is more for performance. As for SQL if the connection string differs you won't share a connection. Remember writing a tool when i was in support to show/test user connection pooling to SQL and it was working. Never saw where you don't want it. And if it is on, depending on the DB it will be within the DB routines managed by the DB client routines...

@dand33: The problem is that i cant build a singletone function through which i will establish the db connection once before all tests start then use the existing connection to execute the required query. The singletone function seems will keep establish the connection for each test no matter if you add it in global setup or not

The problem is that i cant build a singletone function through which i will establish the db connection once before all tests start then use the existing connection to execute the required query.

The singletone function seems will keep establish the connection for each test no matter if you add it in global setup or not

Why doesn't a singleton work?

Also why can't the singleton check if dbConnection == null. We all know what happens when assumptions are made. I'm more C# and would think a lock to wrap the db init code. Check if the dbConnectin == null, create a lock and init the db connection. Should never get more than one conection then?

@amrsa: I'm having this same issue. I'm finding that each test is isolated and I cannot create a single mock DB instance that works across all tests. If I use fixtures, it recreates the mock DB on every test. If I use globalSetup or dependencies, the mock database doesn't live long enough to be used by any test. I tried running it as a webServer but so far no luck. @amrsa what did you end up doing?

I'm having this same issue. I'm finding that each test is isolated and I cannot create a single mock DB instance that works across all tests. If I use fixtures, it recreates the mock DB on every test. If I use globalSetup or dependencies, the mock database doesn't live long enough to be used by any test. I tried running it as a webServer but so far no luck. @amrsa what did you end up doing?

@amrsa @??? Any luck with this, I am having same issue, I use a new broswer instance in each worker. I run tests in parallel, but i want my db connection pool to be available to all workers, and tests within workers, no new connection should be created via each test in each worker

I think the execution model makes having anything be truly ‘global’ unlikely because each worker is independent.

The best I can come up with is having a connection pool as a worker fixture and the client as a test fixture. Or having a service external to the tests. In my case I have a service that runs in the background and exposes an api that the tests interact with not sure how that would integrate with db connections though.

dano095069
dano095069

Connection pooling depending on what we are talking about, working on say MSSQL and MDAC SQL's connection pooling is down below where you'll be able to access and pass around, even worse you have a bunch of security issues sharing and passing them around if you desire. Connection pooling, while i can only speak specifically to SQL's connection pooling, it is located deeper down in the DB provider then you'll be able to utilize from what i know.

Answer

Sure, you can set up a single database pool connection for all your tests using the globalSetup or beforeAll hook in @playwright/test.

First, create a global.setup.ts file at your project's root level. This file should export a function that initializes your database pool connection and stores it in a global variable. Here's an example:

// global.setup.ts
import { Pool } from 'your-database-library';

let dbPool: Pool;

export default async function globalSetup(config: any) {
  dbPool = new Pool(config.databaseOptions);
}

Next, specify the globalSetup option in your Playwright config file (playwright.config.ts) and provide the path to your global.setup.ts file:

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  globalSetup: './global.setup.ts',
});

This way, the globalSetup function will run once before all tests, establishing a single database pool connection. Each test can then access this shared dbPool variable for their database operations.

Remember, if you're using multiple workers with parallel execution, each worker will have its own instance of the global setup. If you want a single database pool connection per worker, initialize the connection in the beforeAll hook instead.

This efficient sharing of resources ensures consistent behavior across your test suite. For more tips on efficient testing with Playwright, check out this blog post.

Related Discord Threads

TwitterGitHubLinkedIn
AboutQuestionsDiscord ForumBrowser ExtensionTagsQA Jobs

Rayrun is a community for QA engineers. I am constantly looking for new ways to add value to people learning Playwright and other browser automation frameworks. If you have feedback, email [email protected].