Я могу сократить свой пост при необходимости
Я использую транзакцию pg-обещание для вставки «устройства» и всей его части (например, системы, диска, ...). Транзакция работает ... но только в первый раз . После этого мой сервер больше не может взаимодействовать с БД (ни вставить, ни выбрать).
Вот вывод pg-monitor с этими шагами
Thu Jul 11 2019 14:26:57 GMT+0200 (GMT+02:00) : server is listening on 9000
14:27:11 connect(hidden@hidden); useCount: 0
14:27:11 insert into "public"."roles"("name") values('Test') RETURNING *
14:27:11 disconnect(hidden@hidden)
14:27:15 connect(hidden@hidden); useCount: 1
14:27:15 insert into "public"."roles"("name") values('Test2') RETURNING *
14:27:15 disconnect(hidden@hidden)
14:27:18 connect(hidden@hidden); useCount: 2
14:27:18 tx(Insert-New-Device)/start
14:27:18 tx(Insert-New-Device): begin
14:27:18 tx(Insert-New-Device): insert into "public"."devices"("smanufacturer") values('HP') RETURNING *
14:27:18 tx(Insert-New-Device): insert into "public"."systems"("deviceid","distributionid","archid","smanufacturer") values(15,3,2,'Microsoft Corporation') RETURNING *
14:27:18 tx(Insert-New-Device): commit
14:27:18 tx(Insert-New-Device)/end; duration: .046, success: true
14:27:18 disconnect(hidden@hidden)
14:27:20 connect(hidden@hidden); useCount: 3
14:27:20 tx(Insert-New-Device)/start
14:27:20 tx(Insert-New-Device): savepoint level_1
14:27:20 error: SAVEPOINT can only be used in transaction blocks
tx(Insert-New-Device): savepoint level_1
14:27:20 tx(Insert-New-Device)/end; duration: .011, success: false
14:27:20 disconnect(hidden@hidden)
ошибка
devices.add
бросок
Ошибка: SAVEPOINT может использоваться только в блоках транзакций
roles.add
бросок
Ошибка: запрос об освобожденном или потерянном соединении
РЕДАКТИРОВАТЬ: обнаружена проблема
Проблема в моих репозиториях. В pg-promise-demo каждое хранилище экспортирует классы, поэтому инициализация БД использует ключевое слово new
в событии расширения для их создания.
Мои репо не классы. Я пытался преобразовать их в классы, и это работает
До (не работает)
. / Дб / репо / devices.js
'use strict';
var Database = null, pgp = null, Collections = null;
async function add(params) {
return Database.tx('Insert-New-Device', async t => {
let system = null;
const query = pgp.helpers.insert(params.data.device, Collections.insert) + " RETURNING *";
let device = await t.one(query);
// if a system is present, insert with diviceId and return
if(params.data.system) {
params.data.system.deviceid = device.deviceid;
system = await t.systems.InsertOne(params);
}
return {device, system};
})
.catch(ex => {
throw ex;
});
}
function createColumnsets() { /* hidden for brevity */ }
// rpc methods
const expose = {
'devices.insert': add
}
const DevicesRepository = {
expose, // expose methods as "rpc methods"
InsertOne: add // internal use (by another repo for example : Database.devices.InsertOne())
};
module.exports = (db, pgpLib) => {
Database = db;
pgp = pgpLib;
Collections = createColumnsets();
return DevicesRepository;
}
. / Дб / index.js.js
'use strict';
const promise = require('bluebird');
const repos = {
Roles: require('./repos/roles'),
Systems: require('./repos/systems'),
Devices: require('./repos/devices')
}
const config = require('./conf');
const initOptions = {
promiseLib: promise,
extend(obj, dc) {
obj.roles = repos.Roles(obj, pgp);
obj.systems = repos.Systems(obj, pgp);
obj.devices = repos.Devices(obj, pgp);
}
};
const pgp = require('pg-promise')(initOptions);
const monitor = require('pg-monitor');
monitor.attach(initOptions);
const db = pgp(config);
const methods = Object.assign({}, db.roles.expose, db.systems.expose, db.devices.expose );
module.exports = {
methods
}
Сейчас (работает без ошибок)
devices.js
'use strict';
class RolesRepository {
constructor(db, pgp) {
this.Database = db;
this.pgp = pgp;
this.Collections = createColumnsets(pgp);
this.expose = {
'roles.insert': this.InsertOne.bind(this)
}
}
makeInsertQuery(role) {
return this.pgp.helpers.insert(role, this.Collections.insert);
}
async InsertOne(params) {
let query = this.makeInsertQuery(params.data);
if(params.return) query += " RETURNING *";
return this.Database.any(query)
.then(data => { return data; })
.catch(ex => { throw ex; });
}
}
function createColumnsets(pgp) { /* hidden for brevity */ }
module.exports = RolesRepository
. / Дб / index.js
'use strict';
const promise = require('bluebird');
//const repos = require('./repos'); // ./repos/index.js
const repos = {
Roles: require('./roles'),
Systems: require('./systems'),
Devices: require('./devices'),
};
const config = { /* hidden */ };
const initOptions = {
promiseLib: promise,
extend(obj, dc) {
obj.roles = new repos.Roles(obj, pgp);
obj.systems = new repos.Systems(obj, pgp);
obj.devices = new repos.Devices(obj, pgp);
}
};
const pgp = require('pg-promise')(initOptions);
const monitor = require('pg-monitor');
monitor.attach(initOptions);
const db = pgp(config);
// expose db methods as rpc call
const methods = Object.assign({},
db.roles.expose,
db.systems.expose,
db.devices.expose,
);
module.exports = {
methods
}