KnexTimeoutError при использовании knex.transactionProvider () - PullRequest
0 голосов
/ 02 апреля 2020

Используя соответствующие файлы ниже, я пытаюсь внедрить транзакции Knex в мой проект . Тем не менее я получаю следующую ошибку:

KnexTimeoutError: Knex: Тайм-аут на установление соединения. Бассейн, вероятно, полон. Вам не хватает .transacting (trx) вызова? в Client_SQLite3.acquireConnection (/c/Users/Raj/Projects/testserver/node_modules/knex/lib/client.js:347:26)

auth / методов. js

const bcrypt = require("bcrypt");
const knex = require("../db/connection");
const passport = require("./passportLocalStrategy");

async function createUser(req, res) {
  console.log("we're in createUser");
  try {
    const errors = validateData(req);
    if (errors.length > 0) throw errors;

    const salt = bcrypt.genSaltSync();
    const hash = bcrypt.hashSync(req.body.password, salt);

    console.log("trying to insert user with knex");
    const trxProvider = knex.transactionProvider();
    const trx = await trxProvider();
    return trx("users").insert({
      name: req.body.name,
      email: req.body.email,
      username: req.body.username,
      password: hash,
    });
  } catch (errors) {
    console.log("error when inserting user with knex");
    // return 400 error
    return errors;
  }
}

function validateData(req) {
  console.log("validating data");
  let errors = [];
  if (!req.body.name) errors.push({ text: "Please enter name" });
  if (!req.body.email) errors.push({ text: "Please enter email" });
  if (!req.body.username) errors.push({ text: "Please enter username"})
  if (req.body.password != req.body.password_confirm)
    errors.push({ text: "Passwords do not match" });
  if (req.body.password < 4)
    errors.push({ text: "Password must be at least 4 characters" });
  return errors;
}

async function login(req, res, next) {
  console.log("logging in");
  await passport.authenticate("local", function (err, user, info) {
    if (err) {
      console.log("error 1")
      return next(err);
    }
    if (!user) {
      console.log("error 2")
      return res.redirect("/login");
    }
    req.login(user, function (err) {
      if (err) {
        console.log("error 3")
        return next(err);
      }
      const user_data = {
        email: req.user.email,
        username: req.user.username,
        name: req.user.name,
        user_since: req.user.created_at,
      };
      console.log("returning user_data")
      return user_data;
    });
  })(req, res, next);
}

module.exports = {
  createUser,
  selectByUsername,
  login,
};

auth / passportLocalStrategy. js

const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;

const init = require("./passportSessionConfig");
const knex = require("../db/connection");
const authUtils = require("./utils");

// const options = {};

init();

console.log("passport localstrategy loaded");

passport.use(
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
    },
    function (username, password, done) {
      console.log("we're in passportLocalStrategy");
      console.log(username);
      // check to see if the username exists
      knex("users")
        .where({ email: username })
        .orWhere({ username })
        .first()
        .then((results) => {
          console.log("line 24 ", results);
          console.log("within passportstrategy");
          if (!results) {
            console.log("no results");
            return done(null, false);
          }
          if (!authUtils.comparePass(password, results.password)) {
            console.log("PASSWORD DOESNT MATCH!");
            return done(null, false);
          } else {
            console.log("PASSWORD MATCHES!!");
            return done(null, results);
          }
        })
        .catch((err) => {
          console.log("caught an error!!!");
          return done(err);
        });
    }
  )
);

module.exports = passport;

маршрутов / пользователей. js

const express = require("express");
const router = express.Router();
const knex = require("../db/connection");
const passport = require("../auth/passportLocalStrategy");
const authUtils = require("../auth/utils");
const authMethods = require("../auth/methods");

router.post("/api/register", async (req, res, next) => {
  try {
    const ids = await authMethods.createUser(req, res);
    console.log("got ids: ")
    console.log(ids)
    const currentUser = authMethods.login(req, res, next);
    return res.status(200).send({ currentUser });
  } catch (errors) {
    // return 500 error
    console.log("500 error")
    console.log(errors)
    return res.status(500).send({ errors });
  }
});

router.post("/api/login", (req, res, next) => {
  return authMethods.login(req, res, next);
});

router.post("/api/logout", (req, res) => {
  console.log("inside logout");
  req.logout();
  req.flash("success_msg", "Logout successful");
  return res.send({});
});

module.exports = router;

Это фрагмент кода из документов Knex Я пытаюсь подражать:

// Does not start a transaction yet
const trxProvider = knex.transactionProvider();

const books = [
  {title: 'Canterbury Tales'},
  {title: 'Moby Dick'},
  {title: 'Hamlet'}
];

// Starts a transaction
const trx = await trxProvider();
const ids = await trx('catalogues')
  .insert({name: 'Old Books'}, 'id')
books.forEach((book) => book.catalogue_id = ids[0]);
await  trx('books').insert(books);

// Reuses same transaction
const sameTrx = await trxProvider();
const ids2 = await sameTrx('catalogues')
  .insert({name: 'New Books'}, 'id')
books.forEach((book) => book.catalogue_id = ids2[0]);
await sameTrx('books').insert(books);

Что не так с моим кодом?

1 Ответ

1 голос
/ 02 апреля 2020

Вам нужно trx.commit() или trx.rollback(new Error('fail')), когда вам больше не нужна транзакция. Теперь он остается открытым, и соединение никогда не прерывается.

Также нет никаких причин, по которым вам нужно было бы использовать поставщика транзакций в вашем случае. Вы можете просто выполнить транзакцию следующим образом:

async function createUser(req, res) {
  console.log("we're in createUser");
  try {
    const errors = validateData(req);
    if (errors.length > 0) throw errors;

    const salt = bcrypt.genSaltSync();
    const hash = bcrypt.hashSync(req.body.password, salt);

    console.log("trying to insert user with knex");
    await knex.transcation(trx => {
      return trx("users").insert({
        name: req.body.name,
        email: req.body.email,
        username: req.body.username,
        password: hash,
      });
    });
  } catch (errors) {
    console.log("error when inserting user with knex");
    // return 400 error
    return errors;
  }
}

, и на самом деле, поскольку вы делаете только один запрос на вставку, вам даже не нужна транзакция для этого. Это так же безопасно:

      await knex("users").insert({
        name: req.body.name,
        email: req.body.email,
        username: req.body.username,
        password: hash,
      });
...