Zoeken op website

node.js - Hoe postgresql-verbindingen te poolen in nodejs met het facade-ontwerppatroon?


Hallo, ik schrijf een eenvoudige webapplicatie met een ontwerp vergelijkbaar met het facade-ontwerppatroon. De applicatie is geschreven in Typescript met behulp van Node.js, Express.js, node-postgres en Inversify. Stel dat ik dit eenvoudige voorbeeld heb

Router.ts

router.get('/test', testController.test);

TestController.ts

import { Request, Response } from 'express';
import { ITestUC } from '../usecase/TestUC';
import { di } from '../core/Di';
import { TYPES } from '../core/Types';

class TestController {

    public async test(req: Request, res: Response, next: Function) {
        const uc = di.get<ITestUC>(TYPES.ITestUC);
        await uc.run();
        res.send({ data:1 });
    }
}

export const testController = new TestController();

TestUC.ts

import "reflect-metadata";
import { injectable, interfaces } from "inversify";
import { di } from "../core/Di";
import { TYPES } from "../core/Types";

import { ITestManager1 } from "../library/Test/TestManager1";
import { ITestManager2 } from "../library/Test/TestManager2";
import { PoolClient } from "pg";
import { PostgresClient, IPostgresClient } from "../core/PostgresClient";
import { IPostgresPool } from "../core/PostgresPool";

function db(transaction: boolean) {
    return (target: any, property: string, descriptor: TypedPropertyDescriptor<() => void>) => {
        const fn = descriptor.value;
        if(!fn) return;
        descriptor.value = async function (){
            let poolClient: PoolClient,
                postgresClient: PostgresClient = new PostgresClient();

            try {
                poolClient = await di.get<IPostgresPool>(TYPES.IPostgresPool).pool.connect();
                postgresClient.set(poolClient);
                di.rebind<IPostgresClient>(TYPES.IPostgresClient).toDynamicValue((context: interfaces.Context) => { return postgresClient });

                if (transaction) postgresClient.begin();

                await fn.apply(this);

                if (transaction) postgresClient.commit();
            } catch (e) {
                if (transaction) postgresClient.rollback();
                throw e;
            } finally { 
                postgresClient.get().release();
            }
        }
    }
}

@injectable()
export class TestUC implements ITestUC {
    @db(true)
    public async run(): Promise<void> {
        const manager1 = await di.get<ITestManager1>(TYPES.ITestManager1);
        manager1.test1('m1');

        const manager2 = await di.get<ITestManager2>(TYPES.ITestManager2);
        manager2.test1('m2');
    }
}

export interface ITestUC {
    run(): Promise<void>
}

TestManager1.ts

import { injectable, inject} from "inversify";
import "reflect-metadata";
import { TYPES } from "../../core/Types";
import { ITestSql1 } from "./TestSql1";

@injectable()
export class TestManager1 implements ITestManager1 {
    @inject(TYPES.ITestSql1) private sql: ITestSql1;

    public async test1(value: string) {
        await this.sql.test1(value);
    }
}

export interface ITestManager1 {
    test1(value: string)
}

TestSql1.ts

import { injectable, inject } from "inversify";
import "reflect-metadata";
import { IPostgresClient } from "../../core/PostgresClient";
import { TYPES } from "../../core/Types";

@injectable()
export class TestSql1 implements ITestSql1{
    @inject(TYPES.IPostgresClient) db: IPostgresClient;

    public async test1(value: string) {
        const query = {
            name: 'insert-test',
            text: `
                INSERT INTO pr.test (
                    process,
                    operation,
                    key
                ) VALUES (
                    $1,
                    $2,
                    $3
                )`,
            values: [
                this.db.get()['processID'], 
                1, 
                value
            ]
        };
        await this.db.get().query(query);
    }
}

export interface ITestSql1 {
    test1(value: string)
}

PostgresClient.ts

import { PoolClient } from "pg";

export class PostgresClient implements IPostgresClient  {
    private client: PoolClient;

    get(): PoolClient {
        return this.client;
    }

    set(client: PoolClient) {
        this.client = client;
    }

    async begin() {
        await this.client.query('BEGIN');
    }

    async commit() {
        await this.client.query('COMMIT');
    }

    async rollback() {
        await this.client.query('ROLLBACK');
    }
}

export interface IPostgresClient {
    get(): PoolClient;
    set(client: PoolClient);
    commit();
    rollback();
    begin();
}

TestManager2.ts en TestSql2.ts zijn in feite hetzelfde als TestManager1.ts en TestSql1.ts

Mijn probleem is dat elke aanvraag lijkt slechts één dezelfde PostgreSQL-verbinding uit de pool te gebruiken (getest met JMeter) en alle API-aanvragen te serialiseren. De pool maakt zelfs geen andere verbindingen met PostgreSQL aan. Het lijkt alsof andere aanvragen wachten op het einde van de vorige aanvraag of het vrijgeven van de PostgreSQL-verbinding.

Hoe een verbinding (transactie) voor elke aanvraag te instantiëren met de node-postgres pool en tegelijkertijd andere aanvragen niet te blokkeren?

Is deze code blokkerend? Of heb ik iets verkeerd begrepen in de documentatie? Of is dit ontwerp gewoon niet geschikt voor nodejs? Ik weet het echt niet en zit al een week vast.