когда отключать и когда заканчивать пг клиент или пул - PullRequest
0 голосов
/ 24 мая 2018

Мой стек - это узел, экспресс и модуль pg.Я действительно пытаюсь понять с помощью документации и некоторых устаревших учебников. Я не знаю, когда и как отключить и завершить работу клиента.

Для некоторых маршрутов я решил использовать пул.Это мой код

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();
    })
});

В маршрутах CMS я использую клиента вместо пула, который имеет привилегии db, отличные от пула.

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);
      });
  })
}

В этом случае, если я получаюa username already used и попробуйте повторно опубликовать с другим именем пользователя, запрос getUser никогда не запускается и страница зависает.Если я уберу client.end(); из обеих функций, он будет работать.

Я в замешательстве, поэтому, пожалуйста, посоветуйте, как и когда отключить и полностью завершить пул или клиента.Любая подсказка или объяснение или учебник будут оценены.

Спасибо

Ответы [ 3 ]

0 голосов
/ 31 мая 2018

Не следует отключать пул при каждом запросе, предполагается, что пул подключений используется для «горячих» подключений.

У меня обычно глобальное подключение при запуске и закрытие подключения к пулу (если) остановка приложения;вам просто нужно освобождать соединение из пула каждый раз, когда запрос заканчивается, как вы уже делаете, и использовать тот же пул также в функции signup.

Иногда мне нужно сохранить соединения, я использую оболочкук функции запроса, которая проверяет, активно ли соединение перед выполнением запроса, но это просто оптимизация.

В случае, если вы не хотите управлять открытием / закрытием соединений / пула или выпуска, вы можетепопробуйте https://github.com/vitaly-t/pg-promise, он управляет всем этим беззвучно и работает хорошо.

0 голосов
/ 31 мая 2018

Во-первых, из 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
      })
  })

Этот код / ​​конструкция достаточен / для работы вашего пула, обеспечивая твоя вещь здесь вещей.Если вы закроете свое приложение, соединение будет зависать нормально, поскольку пул создан хорошо, точно не зависает, даже если он обеспечивает ручной способ зависания, см. Последний раздел статьи .Также обратите внимание на предыдущий красный раздел, в котором написано «Вы всегда должны возвращать клиента ...», чтобы принять

  • обязательную client.release() инструкцию
  • перед тем, как получить доступ к аргументу.
  • вы включаете / закрываете клиента в своих обратных вызовах.

Затем из pg.client документации *:

Простой текстовый запрос с обещанием

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())

мне кажется самым ясным синтаксисом:

  • вы заканчиваете клиента независимо от результатов.
  • вы получаете доступ к результату до окончания клиента.
  • вы не закрываете / не закрываете клиента в своих обратных вызовах

Именно такой тип выбора междудва синтаксиса, которые могут на первый взгляд сбить с толку, но в этом нет ничего волшебного, это синтаксис конструкции реализации.Сосредоточьтесь на ваших обратных вызовах и запросах, а не на этих конструкциях, просто выберите наиболее элегантный для ваших глаз и подпишите его своим кодом.

* Я добавилкомментарии // ваш ххх здесь для наглядности

0 голосов
/ 27 мая 2018

Это довольно просто, клиентское соединение (одиночное соединение) открывается, запрашиваете его, как только вы закончите, вы завершаете его.

В случае mysql концепция пула другая:вы должны .release () подключиться обратно к пулу, как только вы закончите с ним, но похоже, что с pg это другая история:

Из проблемы на репозитории github: Невозможно использовать пул после вызова end в пуле # 1635

"Невозможно использовать пул после вызова end в пуле"

Нельзя повторно использовать пул после его закрытия (т. Е. После вызова функции .end ()).Вам нужно будет воссоздать пул и отказаться от старого.

Самый простой способ иметь дело с пулом в лямбде - вообще не делать этого. Пусть ваши взаимодействия с базой данных создадут свои собственные соединения и закроют их, когда они будут сделаны. В любом случае вы не сможете поддерживать пул между циклами замораживания / оттаивания, так как базовые сокеты TCP будут закрыты.

Если открытие / закрытие соединений становится проблемой производительности, тогда посмотрите на настройку внешнего пула, такого как pgbouncer.

Так что я бы сказал, что ваш лучший вариант - не завершать пул, если вы не выключаете сервер

...