Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection Pool reset, due to connection parameters change, during operation #66

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions locales/en-US/postgresql.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
"label": {
"name": "Name",
"host": "Host",
"hostWatch": "Watch host changes",
"port": "Port",
"portWatch": "Watch port changes",
"database": "Database",
"databaseWatch": "Watch database changes",
"ssl": "SSL",
"sslWatch": "Watch SSL changes",
"user": "User",
"userWatch": "Watch user changes",
"password": "Password",
"passwordWatch": "Watch password changes",
"applicationName": "Application name",
"max": "Maximum size",
"idle": "Idle Timeout",
Expand Down
88 changes: 80 additions & 8 deletions postgresql.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,30 @@
<input type="hidden" id="node-config-input-hostFieldType" />
</div>
<div class="form-row">
<label for="node-config-input-port">
<span data-i18n="postgresql.label.port"></span>
</label>
<input type="text" id="node-config-input-port" data-i18n="[placeholder]postgresql.placeholder.port" style="width: 80%;" />
<input type="hidden" id="node-config-input-portFieldType" />
</div>
<label for="node-config-input-hostWatch">
<span ""></span>
</label>
<input type="checkbox" id="node-config-input-hostWatch" style="display: inline-block; width: auto; vertical-align: top;" />
<label for="node-config-input-hostWatch" style="width: auto;">
<span data-i18n="postgresql.label.hostWatch"></span>
</label>
</div>
<div class="form-row">
<label for="node-config-input-port">
<span data-i18n="postgresql.label.port"></span>
</label>
<input type="text" id="node-config-input-port" data-i18n="[placeholder]postgresql.placeholder.port" style="width: 80%;" />
<input type="hidden" id="node-config-input-portFieldType" />
</div>
<div class="form-row">
<label for="node-config-input-portWatch">
<span ""></span>
</label>
<input type="checkbox" id="node-config-input-portWatch" style="display: inline-block; width: auto; vertical-align: top;" />
<label for="node-config-input-portWatch" style="width: auto;">
<span data-i18n="postgresql.label.portWatch"></span>
</label>
</div>
<div class="form-row">
<label for="node-config-input-database">
<i class="fa fa-database"></i>
Expand All @@ -35,12 +53,30 @@
<input type="hidden" id="node-config-input-databaseFieldType" />
</div>
<div class="form-row">
<label for="node-config-input-ssl" style="width: auto;margin-right: 72px;">
<label for="node-config-input-databaseWatch">
<span ""></span>
</label>
<input type="checkbox" id="node-config-input-databaseWatch" style="display: inline-block; width: auto; vertical-align: top;" />
<label for="node-config-input-databaseWatch" style="width: auto;">
<span data-i18n="postgresql.label.databaseWatch"></span>
</label>
</div>
<div class="form-row">
<label for="node-config-input-ssl">
<span data-i18n="postgresql.label.ssl"></span>
</label>
<input type="text" id="node-config-input-ssl" style="display: inline-block; width: auto; vertical-align: top;" />
<input type="text" id="node-config-input-ssl" data-i18n="[placeholder]postgresql.placeholder.ssl" style="width: 80%;" />
<input type="hidden" id="node-config-input-sslFieldType" />
</div>
<div class="form-row">
<label for="node-config-input-sslWatch">
<span ""></span>
</label>
<input type="checkbox" id="node-config-input-sslWatch" style="display: inline-block; width: auto; vertical-align: top;" />
<label for="node-config-input-sslWatch" style="width: auto;">
<span data-i18n="postgresql.label.sslWatch"></span>
</label>
</div>
</div>
<div id="postgresql-config-tab-security" style="display: none;">
<div class="form-row">
Expand All @@ -51,6 +87,15 @@
<input type="text" id="node-config-input-user" data-i18n="[placeholder]postgresql.placeholder.user" style="width: 80%;" />
<input type="hidden" id="node-config-input-userFieldType" />
</div>
<div class="form-row">
<label for="node-config-input-userWatch">
<span ""></span>
</label>
<input type="checkbox" id="node-config-input-userWatch" style="display: inline-block; width: auto; vertical-align: top;" />
<label for="node-config-input-userWatch" style="width: auto;">
<span data-i18n="postgresql.label.userWatch"></span>
</label>
</div>
<div class="form-row">
<label for="node-config-input-password">
<i class="fa fa-lock"></i>
Expand All @@ -59,6 +104,15 @@
<input type="password" id="node-config-input-password" data-i18n="[placeholder]postgresql.placeholder.password" style="width: 80%;" />
<input type="hidden" id="node-config-input-passwordFieldType" />
</div>
<div class="form-row">
<label for="node-config-input-passwordWatch">
<span ""></span>
</label>
<input type="checkbox" id="node-config-input-passwordWatch" style="display: inline-block; width: auto; vertical-align: top;" />
<label for="node-config-input-passwordWatch" style="width: auto;">
<span data-i18n="postgresql.label.passwordWatch"></span>
</label>
</div>
</div>
<div id="postgresql-config-tab-pool" style="display: none;">
<div class="form-row">
Expand Down Expand Up @@ -111,24 +165,36 @@
hostFieldType: {
value: 'str',
},
hostWatch: {
value: false,
},
port: {
value: 5432,
},
portFieldType: {
value: 'num',
},
portWatch: {
value: false,
},
database: {
value: 'postgres',
},
databaseFieldType: {
value: 'str',
},
databaseWatch: {
value: false,
},
ssl: {
value: false,
},
sslFieldType: {
value: 'bool',
},
sslWatch: {
value: false,
},
applicationName: {
value: '',
},
Expand Down Expand Up @@ -159,13 +225,19 @@
userFieldType: {
value: 'str',
},
userWatch: {
value: false,
},
password: {
value: '',
},
passwordFieldType: {
// TODO: https://nodered.org/docs/creating-nodes/credentials
value: 'str',
},
passwordWatch: {
value: false,
},
},
label: function () {
return this.name || this.user + '@' + this.host + ':' + this.port + '/' + this.database;
Expand Down
95 changes: 82 additions & 13 deletions postgresql.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,63 @@ module.exports = function (RED) {
}
}

function getParam(cnfg, key) {
switch (key) {
case 'host':
return getField(cnfg, cnfg.hostFieldType, cnfg.host);
case 'port':
return getField(cnfg, cnfg.portFieldType, cnfg.port);
case 'database':
return getField(cnfg, cnfg.databaseFieldType, cnfg.database);
case 'ssl':
return getField(cnfg, cnfg.sslFieldType, cnfg.ssl);
case 'user':
return getField(cnfg, cnfg.userFieldType, cnfg.user);
case 'password':
return getField(cnfg, cnfg.passwordFieldType, cnfg.password);
case 'appname':
return getField(cnfg, cnfg.applicationNameType, cnfg.applicationName);
case 'max':
return getField(cnfg, cnfg.maxFieldType, cnfg.max);
case 'idle':
return getField(cnfg, cnfg.idleFieldType, cnfg.idle);
case 'timeout':
return getField(cnfg, cnfg.connectionTimeoutFieldType, cnfg.connectionTimeout);
}
return cnfg;
}

function getDbAccessData(cnfg) {
return {
user: getParam(cnfg, 'user'),
password: getParam(cnfg, 'password'),
host: getParam(cnfg, 'host'),
port: getParam(cnfg, 'port'),
database: getParam(cnfg, 'database'),
ssl: getParam(cnfg, 'ssl'),
application_name: getParam(cnfg, 'appname'),
max: getParam(cnfg, 'max'),
idleTimeoutMillis: getParam(cnfg, 'idle'),
connectionTimeoutMillis: getParam(cnfg, 'timeout'),
}
}

function PostgreSQLConfigNode(n) {
const node = this;
RED.nodes.createNode(node, n);

// Build an array of keys of parameters to be watched
const watchFlags = {
host: n.hostWatch,
port: n.portWatch,
database: n.databaseWatch,
ssl: n.sslWatch,
user: n.userWatch,
password: n.passwordWatch,
}
node.watchList = [];
for (const key in watchFlags) { if (watchFlags[key] === true) node.watchList.push(key) };

node.name = n.name;
node.host = n.host;
node.hostFieldType = n.hostFieldType;
Expand All @@ -76,19 +130,11 @@ module.exports = function (RED) {
node.connectionTimeout = n.connectionTimeout;
node.connectionTimeoutFieldType = n.connectionTimeoutFieldType;

this.pgPool = new Pool({
user: getField(node, n.userFieldType, n.user),
password: getField(node, n.passwordFieldType, n.password),
host: getField(node, n.hostFieldType, n.host),
port: getField(node, n.portFieldType, n.port),
database: getField(node, n.databaseFieldType, n.database),
ssl: getField(node, n.sslFieldType, n.ssl),
application_name: getField(node, n.applicationNameType, n.applicationName),
max: getField(node, n.maxFieldType, n.max),
idleTimeoutMillis: getField(node, n.idleFieldType, n.idle),
connectionTimeoutMillis: getField(node, n.connectionTimeoutFieldType, n.connectionTimeout),
});
this.pgPool.on('error', (err, _) => {
node.dbAccessData = getDbAccessData(node);

node.pgPool = new Pool(node.dbAccessData);

node.pgPool.on('error', (err, _) => {
node.error(err.message);
});
}
Expand All @@ -105,6 +151,7 @@ module.exports = function (RED) {
node.config = RED.nodes.getNode(config.postgreSQLConfig) || {
pgPool: {
totalCount: 0,
end: null
},
};

Expand Down Expand Up @@ -155,6 +202,28 @@ module.exports = function (RED) {
updateStatus(0, false);

node.on('input', async (msg, send, done) => {

// Scan watchList array, check for parameter changes
let changed = false;
let newParam = undefined;
for (const key of node.config.watchList) {
const param = node.config.dbAccessData[key];
newParam = getParam(node.config, key);
if (newParam !== param) {
node.config.dbAccessData[key] = newParam;
changed = true;
};
};

// Reset connections pool, if needed
if (changed || msg.reconnect) {
if (node.config.pgPool.end !== null) {
node.config.pgPool.end();
}
node.config.dbAccessData = getDbAccessData(node.config);
node.config.pgPool = new Pool(node.config.dbAccessData);
}

// 'send' and 'done' require Node-RED 1.0+
send = send || function () { node.send.apply(node, arguments); };

Expand Down