我有一个NodeJS服务,该服务使用PostGreSQL的事件通知功能来侦听数据库中的某些操作,然后执行Node函数作为响应。如何设置它已在node-postgres软件包的文档中进行了说明,乍一看似乎功能还不错。
问题在于,运行Node服务(正在侦听我的数据库)一段时间后,它会停止侦听数据库。 “一会儿”是指它足够长,以至于每次发生时我都没有确切注意到我上次使用该服务的时间,但这至少需要一两个小时。可能会更长一些……在2-4小时内?
我可以确定,就Postgres而言,过了一会儿,Node服务不再连接到数据库。但是Node服务似乎从未注意到它没有连接……它没有显示错误,也没有触发通常由断开连接(client.on('end',function(){...})
)触发的事件。我无法确定这是由于我在Node中的Pool配置导致的超时,还是数据库正在执行断开连接。但是,我认为因为要实现这一点,在节点代码的设置中存在更多的复杂性,因此在节点侧更有可能。 PostGres端实际上是一些触发函数,它们与node-postgres文档中的基本相同。
当Node服务表现出这种“我不在监听”行为时,它不会显示任何错误甚至消息……而调试Node代码则表明它没有事件跳入处理程序,例如, notificationProcessor()
(如下所示)。因此,我对于在哪里进行调查一无所知。调查的一个挑战是要复制行为,我必须将其设置为运行,然后将其放置一段时间。
这是相关的Node代码。我在NodeJS v8.7.0和v9.0.0中看到了这个问题。我正在使用node-postgres v7.4.3。我看到在Mac和Linux上运行Node的问题。 PostGres 9.4.15在运行Node的单独Linux服务器上运行。
// The PostGres driver for Node needs a setting for the Pool ... not sure why.
pg.defaults.poolSize = 1;
// Load the connection details (user, password, etc.)
var pg_connect = "postgres://" + config.pg_user + ":" + config.pg_pass + "@" + config.pg_server + "/" + config.pg_db;
// Setup the connection pool and ... connect to the database.
var pool = new pg.Pool(
{
connectionString: pg_connect,
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000
}
);
// Critically, pass callback to the connection ... so start
// running the "executionListener()" when it connects.
pool.connect(executionListener);
pool.on(
'error',
function(err,client) {
console.log("\n-{Error!}- " + err.message);
console.log(" \\----> Attempting to re-start Listening!\n");
pool.connect(executionListener);
}
);
// What "channels" to monitor in the database for change events,
// and then what function to call when the event is found.
var monitoredChannels = {
'executions': {
cname: 'executions',
chandler: function(msg) {
console.log("\t[notification on executions] " + JSON.stringify(msg));
newExecution(msg);
},
cquery: {}
},
'updates': {
cname: 'updates',
chandler: function(msg) {
console.log("\t[notification on updates] " + JSON.stringify(msg));
executionUpdate(msg);
},
cquery: {}
}
};
function notificationProcessor(notif) {
var tpayload = notif.payload.split(',');
var resultLength = tpayload.length;
var resultAttributeCount = (resultLength - 1) / 2;
var payloadPointer = - 1;
// What DB table is the notification referencing?
var resultOut = {
'table': tpayload[0]
};
for (var i = 0; i < resultAttributeCount; i++) {
payloadPointer = payloadPointer + 2;
resultOut[tpayload[payloadPointer]] = tpayload[payloadPointer + 1];
}
// Once the data package from the notification is parsed into
// a useful form, we look at the array of channels we're watching,
// and pass the data to the handler for the appropriate channel.
return (monitoredChannels[notif.channel].chandler(resultOut))
}
// This is the main function used to monitor the database for events and
// react to them.
function executionListener(err, client, done) {
// Handle errors in connection... if the connection
// fails, try to reconnect.
if(err) {
console.log(err);
if (done != null) done();
pool.connect(executionListener);
}
console.log("[mPipeRunner] Listening to <" + config.pg_server + "/" + config.pg_db + "/" + config.schema + "> for executions");
// What to do when a notice (error) is sent by database.
client.on('notice', (msg) => console.warn('PGSQL Notice:', msg));
// When PG disconnects for some reason, what to do?
client.on('end',function(){console.log('client disconnected')});
// When PG spits out a notification FROM A CHANNEL WE ARE LISTENING TO...
client.on('notification', notificationProcessor);
// Loop over the channels and initiate LISTENing to each one.
for (var chnl in monitoredChannels) {
var channel = monitoredChannels[chnl];
channel.query = client.query("LISTEN " + channel.cname);
}
};
在此先感谢您的见解!