Skip to content

Commit 58518b6

Browse files
feat(Postgres Node): Options keepAlive and keepAliveInitialDelayMillis (#9067)
1 parent c2f4d7d commit 58518b6

16 files changed

+136
-31
lines changed

packages/nodes-base/nodes/Postgres/PostgresTrigger.functions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ export async function pgTriggerFunction(
8787

8888
export async function initDB(this: ITriggerFunctions | ILoadOptionsFunctions) {
8989
const credentials = await this.getCredentials('postgres');
90+
const options = this.getNodeParameter('options', {}) as {
91+
connectionTimeout?: number;
92+
delayClosingIdleConnection?: number;
93+
};
9094
const pgp = pgPromise({
9195
// prevent spam in console "WARNING: Creating a duplicate database object for the same connection."
9296
noWarnings: true,
@@ -97,8 +101,17 @@ export async function initDB(this: ITriggerFunctions | ILoadOptionsFunctions) {
97101
database: credentials.database as string,
98102
user: credentials.user as string,
99103
password: credentials.password as string,
104+
keepAlive: true,
100105
};
101106

107+
if (options.connectionTimeout) {
108+
config.connectionTimeoutMillis = options.connectionTimeout * 1000;
109+
}
110+
111+
if (options.delayClosingIdleConnection) {
112+
config.keepAliveInitialDelayMillis = options.delayClosingIdleConnection * 1000;
113+
}
114+
102115
if (credentials.allowUnauthorizedCerts === true) {
103116
config.ssl = {
104117
rejectUnauthorized: false,

packages/nodes-base/nodes/Postgres/PostgresTrigger.node.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,33 @@ export class PostgresTrigger implements INodeType {
209209
},
210210
],
211211
},
212+
{
213+
displayName: 'Options',
214+
name: 'options',
215+
type: 'collection',
216+
placeholder: 'Add Option',
217+
default: {},
218+
options: [
219+
{
220+
displayName: 'Connection Timeout',
221+
name: 'connectionTimeout',
222+
type: 'number',
223+
default: 30,
224+
description: 'Number of seconds reserved for connecting to the database',
225+
},
226+
{
227+
displayName: 'Delay Closing Idle Connection',
228+
name: 'delayClosingIdleConnection',
229+
type: 'number',
230+
default: 0,
231+
description:
232+
'Number of seconds to wait before idle connection would be eligible for closing',
233+
typeOptions: {
234+
minValue: 0,
235+
},
236+
},
237+
],
238+
},
212239
],
213240
};
214241

packages/nodes-base/nodes/Postgres/v2/actions/common.descriptions.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ export const optionsCollection: INodeProperties = {
3030
default: 30,
3131
description: 'Number of seconds reserved for connecting to the database',
3232
},
33+
{
34+
displayName: 'Delay Closing Idle Connection',
35+
name: 'delayClosingIdleConnection',
36+
type: 'number',
37+
default: 0,
38+
description: 'Number of seconds to wait before idle connection would be eligible for closing',
39+
typeOptions: {
40+
minValue: 0,
41+
},
42+
},
3343
{
3444
displayName: 'Query Batching',
3545
name: 'queryBatching',

packages/nodes-base/nodes/Postgres/v2/actions/database/deleteTable.operation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { NodeOperationError } from 'n8n-workflow';
88

99
import type {
1010
PgpDatabase,
11+
PostgresNodeOptions,
1112
QueriesRunner,
1213
QueryValues,
1314
QueryWithValues,
@@ -95,7 +96,7 @@ export async function execute(
9596
this: IExecuteFunctions,
9697
runQueries: QueriesRunner,
9798
items: INodeExecutionData[],
98-
nodeOptions: IDataObject,
99+
nodeOptions: PostgresNodeOptions,
99100
_db?: PgpDatabase,
100101
): Promise<INodeExecutionData[]> {
101102
const queries: QueryWithValues[] = [];

packages/nodes-base/nodes/Postgres/v2/actions/database/executeQuery.operation.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import type {
66
} from 'n8n-workflow';
77
import { NodeOperationError } from 'n8n-workflow';
88

9-
import type { PgpDatabase, QueriesRunner, QueryWithValues } from '../../helpers/interfaces';
9+
import type {
10+
PgpDatabase,
11+
PostgresNodeOptions,
12+
QueriesRunner,
13+
QueryWithValues,
14+
} from '../../helpers/interfaces';
1015

1116
import { replaceEmptyStringsByNulls } from '../../helpers/utils';
1217

@@ -46,7 +51,7 @@ export async function execute(
4651
this: IExecuteFunctions,
4752
runQueries: QueriesRunner,
4853
items: INodeExecutionData[],
49-
nodeOptions: IDataObject,
54+
nodeOptions: PostgresNodeOptions,
5055
_db?: PgpDatabase,
5156
): Promise<INodeExecutionData[]> {
5257
items = replaceEmptyStringsByNulls(items, nodeOptions.replaceEmptyStrings as boolean);

packages/nodes-base/nodes/Postgres/v2/actions/database/insert.operation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77

88
import type {
99
PgpDatabase,
10+
PostgresNodeOptions,
1011
QueriesRunner,
1112
QueryValues,
1213
QueryWithValues,
@@ -157,7 +158,7 @@ export async function execute(
157158
this: IExecuteFunctions,
158159
runQueries: QueriesRunner,
159160
items: INodeExecutionData[],
160-
nodeOptions: IDataObject,
161+
nodeOptions: PostgresNodeOptions,
161162
db: PgpDatabase,
162163
): Promise<INodeExecutionData[]> {
163164
items = replaceEmptyStringsByNulls(items, nodeOptions.replaceEmptyStrings as boolean);

packages/nodes-base/nodes/Postgres/v2/actions/database/select.operation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77

88
import type {
99
PgpDatabase,
10+
PostgresNodeOptions,
1011
QueriesRunner,
1112
QueryValues,
1213
QueryWithValues,
@@ -75,7 +76,7 @@ export async function execute(
7576
this: IExecuteFunctions,
7677
runQueries: QueriesRunner,
7778
items: INodeExecutionData[],
78-
nodeOptions: IDataObject,
79+
nodeOptions: PostgresNodeOptions,
7980
_db?: PgpDatabase,
8081
): Promise<INodeExecutionData[]> {
8182
items = replaceEmptyStringsByNulls(items, nodeOptions.replaceEmptyStrings as boolean);

packages/nodes-base/nodes/Postgres/v2/actions/database/update.operation.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { NodeOperationError } from 'n8n-workflow';
88

99
import type {
1010
PgpDatabase,
11+
PostgresNodeOptions,
1112
QueriesRunner,
1213
QueryValues,
1314
QueryWithValues,
@@ -194,7 +195,7 @@ export async function execute(
194195
this: IExecuteFunctions,
195196
runQueries: QueriesRunner,
196197
items: INodeExecutionData[],
197-
nodeOptions: IDataObject,
198+
nodeOptions: PostgresNodeOptions,
198199
db: PgpDatabase,
199200
): Promise<INodeExecutionData[]> {
200201
items = replaceEmptyStringsByNulls(items, nodeOptions.replaceEmptyStrings as boolean);
@@ -279,7 +280,7 @@ export async function execute(
279280
const rowExists = await doesRowExist(db, schema, table, matchValues);
280281
if (!rowExists) {
281282
const descriptionValues: string[] = [];
282-
matchValues.forEach((val, index) => {
283+
matchValues.forEach((_, index) => {
283284
if (index % 2 === 0) {
284285
descriptionValues.push(`${matchValues[index]}=${matchValues[index + 1]}`);
285286
}

packages/nodes-base/nodes/Postgres/v2/actions/database/upsert.operation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { NodeOperationError } from 'n8n-workflow';
88

99
import type {
1010
PgpDatabase,
11+
PostgresNodeOptions,
1112
QueriesRunner,
1213
QueryValues,
1314
QueryWithValues,
@@ -193,7 +194,7 @@ export async function execute(
193194
this: IExecuteFunctions,
194195
runQueries: QueriesRunner,
195196
items: INodeExecutionData[],
196-
nodeOptions: IDataObject,
197+
nodeOptions: PostgresNodeOptions,
197198
db: PgpDatabase,
198199
): Promise<INodeExecutionData[]> {
199200
items = replaceEmptyStringsByNulls(items, nodeOptions.replaceEmptyStrings as boolean);

packages/nodes-base/nodes/Postgres/v2/actions/router.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { configureQueryRunner } from '../helpers/utils';
66
import type { PostgresType } from './node.type';
77

88
import * as database from './database/Database.resource';
9+
import type { PostgresNodeCredentials, PostgresNodeOptions } from '../helpers/interfaces';
910

1011
export async function router(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
1112
let returnData: INodeExecutionData[] = [];
@@ -14,8 +15,8 @@ export async function router(this: IExecuteFunctions): Promise<INodeExecutionDat
1415
const resource = this.getNodeParameter<PostgresType>('resource', 0);
1516
const operation = this.getNodeParameter('operation', 0);
1617

17-
const credentials = await this.getCredentials('postgres');
18-
const options = this.getNodeParameter('options', 0, {});
18+
const credentials = (await this.getCredentials('postgres')) as PostgresNodeCredentials;
19+
const options = this.getNodeParameter('options', 0, {}) as PostgresNodeOptions;
1920
options.nodeVersion = this.getNode().typeVersion;
2021
options.operation = operation;
2122

packages/nodes-base/nodes/Postgres/v2/helpers/interfaces.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,36 @@ export type QueriesRunner = (
3535
items: INodeExecutionData[],
3636
options: IDataObject,
3737
) => Promise<INodeExecutionData[]>;
38+
39+
export type PostgresNodeOptions = {
40+
nodeVersion?: number;
41+
operation?: string;
42+
cascade?: boolean;
43+
connectionTimeout?: number;
44+
delayClosingIdleConnection?: number;
45+
queryBatching?: QueryMode;
46+
queryReplacement?: string;
47+
outputColumns?: string[];
48+
largeNumbersOutput?: 'numbers' | 'text';
49+
skipOnConflict?: boolean;
50+
replaceEmptyStrings?: boolean;
51+
};
52+
53+
export type PostgresNodeCredentials = {
54+
sshAuthenticateWith: 'password' | 'privateKey';
55+
host: string;
56+
port: number;
57+
database: string;
58+
user: string;
59+
password: string;
60+
allowUnauthorizedCerts?: boolean;
61+
ssl?: 'disable' | 'allow' | 'require' | 'verify' | 'verify-full';
62+
sshTunnel?: boolean;
63+
sshHost?: string;
64+
sshPort?: number;
65+
sshPostgresPort?: number;
66+
sshUser?: string;
67+
sshPassword?: string;
68+
privateKey?: string;
69+
passphrase?: string;
70+
};

packages/nodes-base/nodes/Postgres/v2/methods/credentialTest.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
import type {
22
ICredentialsDecrypted,
33
ICredentialTestFunctions,
4-
IDataObject,
54
INodeCredentialTestResult,
65
} from 'n8n-workflow';
76

87
import { Client } from 'ssh2';
98
import { configurePostgres } from '../transport';
109

11-
import type { PgpClient } from '../helpers/interfaces';
10+
import type { PgpClient, PostgresNodeCredentials } from '../helpers/interfaces';
1211

1312
export async function postgresConnectionTest(
1413
this: ICredentialTestFunctions,
1514
credential: ICredentialsDecrypted,
1615
): Promise<INodeCredentialTestResult> {
17-
const credentials = credential.data as IDataObject;
16+
const credentials = credential.data as PostgresNodeCredentials;
1817

1918
let sshClientCreated: Client | undefined = new Client();
2019
let pgpClientCreated: PgpClient | undefined;

packages/nodes-base/nodes/Postgres/v2/methods/listSearch.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type { ILoadOptionsFunctions, INodeListSearchResult } from 'n8n-workflow';
22

33
import { configurePostgres } from '../transport';
4+
import type { PostgresNodeCredentials } from '../helpers/interfaces';
45

56
export async function schemaSearch(this: ILoadOptionsFunctions): Promise<INodeListSearchResult> {
6-
const credentials = await this.getCredentials('postgres');
7+
const credentials = (await this.getCredentials('postgres')) as PostgresNodeCredentials;
78
const options = { nodeVersion: this.getNode().typeVersion };
89

910
const { db, sshClient } = await configurePostgres(credentials, options);
@@ -27,7 +28,7 @@ export async function schemaSearch(this: ILoadOptionsFunctions): Promise<INodeLi
2728
}
2829
}
2930
export async function tableSearch(this: ILoadOptionsFunctions): Promise<INodeListSearchResult> {
30-
const credentials = await this.getCredentials('postgres');
31+
const credentials = (await this.getCredentials('postgres')) as PostgresNodeCredentials;
3132
const options = { nodeVersion: this.getNode().typeVersion };
3233

3334
const { db, sshClient } = await configurePostgres(credentials, options);

packages/nodes-base/nodes/Postgres/v2/methods/loadOptions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import type { ILoadOptionsFunctions, INodePropertyOptions } from 'n8n-workflow';
22

33
import { getTableSchema } from '../helpers/utils';
44
import { configurePostgres } from '../transport';
5+
import type { PostgresNodeCredentials } from '../helpers/interfaces';
56

67
export async function getColumns(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
7-
const credentials = await this.getCredentials('postgres');
8+
const credentials = (await this.getCredentials('postgres')) as PostgresNodeCredentials;
89
const options = { nodeVersion: this.getNode().typeVersion };
910

1011
const { db, sshClient } = await configurePostgres(credentials, options);

packages/nodes-base/nodes/Postgres/v2/methods/resourceMapping.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { ILoadOptionsFunctions, ResourceMapperFields, FieldType } from 'n8n-workflow';
22
import { getEnumValues, getEnums, getTableSchema, uniqueColumns } from '../helpers/utils';
33
import { configurePostgres } from '../transport';
4+
import type { PostgresNodeCredentials } from '../helpers/interfaces';
45

56
const fieldTypeMapping: Partial<Record<FieldType, string[]>> = {
67
string: ['text', 'varchar', 'character varying', 'character', 'char'],
@@ -45,7 +46,7 @@ function mapPostgresType(postgresType: string): FieldType {
4546
export async function getMappingColumns(
4647
this: ILoadOptionsFunctions,
4748
): Promise<ResourceMapperFields> {
48-
const credentials = await this.getCredentials('postgres');
49+
const credentials = (await this.getCredentials('postgres')) as PostgresNodeCredentials;
4950

5051
const { db, sshClient } = await configurePostgres(credentials);
5152

0 commit comments

Comments
 (0)