web-dev-qa-db-fra.com

quand se déconnecter et quand mettre fin à un client ou à un pool pg

Ma pile est noeud, express et le module pg. J'essaie vraiment de comprendre par la documentation et certains tutoriels obsolètes. Je ne sais pas quand et comment se déconnecter et mettre fin à un client.

Pour certains itinéraires, j'ai décidé d'utiliser une piscine. C'est mon code

const pool = new pg.Pool({
  user: 'pooluser',Host: 'localhost',database: 'mydb',password: 'pooluser',port: 5432});

pool.on('error', (err, client) => {
  console.log('error ', err);  process.exit(-1);
});

app.get('/', (req, res)=>{
  pool.connect()
    .then(client => {
      return client.query('select ....')
            .then(resolved => {
              client.release();
              console.log(resolved.rows);
            })
            .catch(e => { 
              client.release();
              console.log('error', e);
            })
      pool.end();
    })
});

Dans les itinéraires du CMS, j'utilise un client au lieu d'un pool disposant de privilèges de base de données différents de ceux du pool.

const client = new pg.Client({
  user: 'clientuser',Host: 'localhost',database: 'mydb',password: 'clientuser',port: 5432});    
client.connect();

const signup = (user) => {
  return new Promise((resolved, rejeted)=>{
    getUser(user.email)
    .then(getUserRes => {
      if (!getUserRes) {
        return resolved(false);
      }            
            client.query('insert into user(username, password) values ($1,$2)',[user.username,user.password])
              .then(queryRes => {
                client.end();
                resolved(true);
              })
              .catch(queryError => {
                client.end();
                rejeted('username already used');
              });
    })
    .catch(getUserError => {
      return rejeted('error');
    });
  }) 
};

const getUser = (username) => {
  return new Promise((resolved, rejeted)=>{
    client.query('select username from user WHERE username= $1',[username])
      .then(res => {
        client.end();
        if (res.rows.length == 0) {
          return resolved(true);
        }
        resolved(false);
      })
      .catch(e => {
        client.end();
        console.error('error ', e);
      });
  })
}

Dans ce cas, si je reçois un username already used Et que j'essaie de publier à nouveau avec un autre nom d'utilisateur, la requête de getUser ne commence jamais et la page se bloque. Si je supprime la client.end(); des deux fonctions, cela fonctionnera.

Je suis confus, alors s'il vous plaît donnez des conseils sur comment et quand déconnecter et mettre fin complètement à un pool ou un client. Toute suggestion, explication ou tutoriel sera apprécié.

Merci

23
slevin

Tout d’abord, à partir de la documentation pg *:

const { Pool } = require('pg')

const pool = new Pool()

// the pool with emit an error on behalf of any idle clients
// it contains if a backend error or network partition happens
pool.on('error', (err, client) => {
  console.error('Unexpected error on idle client', err) // your callback here
  process.exit(-1)
})

// promise - checkout a client
pool.connect()
  .then(client => {
    return client.query('SELECT * FROM users WHERE id = $1', [1]) // your query string here
      .then(res => {
        client.release()
        console.log(res.rows[0]) // your callback here
      })
      .catch(e => {
        client.release()
        console.log(err.stack) // your callback here
      })
  })

Ce code/cette construction est suffisant /pour que votre piscine fonctionne, en fournissant le votre truc ici choses. Si vous fermez votre application, la connexion sera suspendue normalement, puisque le pool est bien créé, il ne faut pas bloquer exactement, même s'il fournit une méthode de suspension manuelle, voir la dernière section de article . Consultez également la section rouge précédente intitulée "Vous devez toujours renvoyer le client ..." pour accepter

  • l'instruction obligatoire client.release()
  • avant d’accéder à la discussion.
  • vous portez/fermez le client dans vos rappels.

Alors , à partir de la documentation pg.client *:

Requête en texte brut avec une promesse

const { Client } = require('pg').Client
const client = new Client()
client.connect()
client.query('SELECT NOW()') // your query string here
  .then(result => console.log(result)) // your callback here
  .catch(e => console.error(e.stack)) // your callback here
  .then(() => client.end())

me semble la syntaxe la plus claire:

  • vous terminez le client quels que soient les résultats.
  • vous accédez au résultat avant ending le client.
  • vous n'imposez pas/ne fermez pas le client dans vos rappels

C'est ce type d'opposition entre les deux syntaxes qui peut semer la confusion, mais il n'y a pas de magie là-dedans, c'est une syntaxe de construction d'implémentation. Concentrez-vous sur vos rappels et requêtes, et non sur ces constructions, prenez simplement le plus élégant pour vos yeux et flux avec votre code.

* J'ai ajouté les commentaires // votre xxx ici pour plus de clarté

12
lucchi

Vous ne devez pas déconnecter le pool à chaque requête, le pool de connexions est supposé être utilisé pour avoir des connexions "à chaud".

J'ai généralement une connexion globale au démarrage et la connexion du pool se ferme à (si) l'application s'arrête; vous devez simplement libérer la connexion du pool à chaque fin de la requête, comme vous le faites déjà, et utiliser le même pool également dans la fonction signup.

Parfois, j'ai besoin de préserver les connexions, j'utilise un wrapper pour la fonction de requête qui vérifie si la connexion est active ou non avant d'exécuter la requête, mais il ne s'agit que d'une optimisation.

Si vous ne voulez pas gérer les connexions ouvertes/fermées/le pool ou la version, vous pouvez essayer https://github.com/vitaly-t/pg-promise , il gère tout cela en silence et ça marche bien.

7

C'est assez simple, une connexion client (connexion unique) s'ouvre, interrogez-la, une fois que vous avez terminé, vous la terminez.

Le concept de pool est différent, dans le cas de mysql: vous devez relâcher () la connexion au pool une fois que vous avez terminé, mais il semble que avec pg soit un histoire différente:

D'après un problème sur le dépôt github: . Impossible d'utiliser un pool après avoir appelé le terminal # 1635 =

"Impossible d'utiliser un pool après avoir appelé sur le pool"

Vous ne pouvez pas réutiliser un pool après sa fermeture (c'est-à-dire après avoir appelé la fonction .end ()). Vous devrez recréer le pool et jeter l'ancien.

Le moyen le plus simple de gérer la mise en commun dans un Lambda est de ne pas le faire du tout. Demandez à vos interactions de base de données de créer leurs propres connexions et de les fermer lorsqu'elles sont terminées. sous-jacent TCP les sockets seraient fermés.

Si l'ouverture/la fermeture des connexions devient un problème de performances, envisagez de configurer un pool externe comme pgbouncer.

Donc, je dirais que votre meilleure option est de ne pas mettre fin au pool, sauf si vous arrêtez le serveur

0
EMX