From 23970f5dcdaaec52a370995a6e7f879a9da9bd8e Mon Sep 17 00:00:00 2001 From: subrat gantayat Date: Sat, 15 Nov 2025 00:06:59 +0530 Subject: [PATCH 1/3] Fixed keyv connect issue with postgresql db. --- app-config.template-local.yaml | 4 +-- packages/backend/package.json | 4 ++- packages/backend/src/cachePlugin.ts | 17 +++++++--- packages/backend/src/cacheService.ts | 48 +++++++++++++++------------- yarn.lock | 17 ++++++++-- 5 files changed, 58 insertions(+), 32 deletions(-) diff --git a/app-config.template-local.yaml b/app-config.template-local.yaml index 8028ff8..79beffa 100644 --- a/app-config.template-local.yaml +++ b/app-config.template-local.yaml @@ -34,7 +34,7 @@ backend: # replace these to match your environment host: ${POSTGRES_HOST} port: ${POSTGRES_PORT} - user: {POSTGRES_USER} + user: ${POSTGRES_USER} password: ${POSTGRES_PASSWORD} ## Uncomment the below github integrations config to add a PAT to try out @@ -82,4 +82,4 @@ essentialLocations: frequencyInMinutes: 120 locations: - type: url - target: https://github.com/TIBCOSoftware/tibco-developer-hub/blob/main/tibco-examples/tibco-essentials.yaml \ No newline at end of file + target: https://github.com/TIBCOSoftware/tibco-developer-hub/blob/main/tibco-examples/tibco-essentials.yaml diff --git a/packages/backend/package.json b/packages/backend/package.json index 0668793..dcc51ea 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -67,6 +67,7 @@ "global-agent": "^3.0.0", "jwt-decode": "^3.1.2", "keyv": "^5.5.0", + "knex": "^3.1.0", "node-gyp": "^10.0.0", "openid-client": "^5.5.0", "pg": "^8.11.3", @@ -75,7 +76,8 @@ "winston-daily-rotate-file": "^5.0.0" }, "devDependencies": { - "@backstage/cli": "^0.33.1" + "@backstage/cli": "^0.33.1", + "@types/pg": "^8.11.3" }, "files": [ "dist" diff --git a/packages/backend/src/cachePlugin.ts b/packages/backend/src/cachePlugin.ts index 5965f3b..2659fa8 100644 --- a/packages/backend/src/cachePlugin.ts +++ b/packages/backend/src/cachePlugin.ts @@ -2,16 +2,25 @@ * Copyright (c) 2023-2025. Cloud Software Group, Inc. All Rights Reserved. Confidential & Proprietary */ -import { createBackendPlugin } from '@backstage/backend-plugin-api'; +import { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; import { KeyvStore } from './cacheService.ts'; +import { Knex } from 'knex'; + +const PLUGIN_ID: string = 'tibco_hub_cache'; export default createBackendPlugin({ pluginId: 'tibco_hub_cache', register(env) { env.registerInit({ - deps: {}, - async init() { - KeyvStore.initialize(); + deps: { + database: coreServices.database, + }, + async init({ database }) { + const knex: Knex = await database.getClient(); + KeyvStore.initialize(knex, PLUGIN_ID); await KeyvStore.keyv.clear(); }, }); diff --git a/packages/backend/src/cacheService.ts b/packages/backend/src/cacheService.ts index e80cb5c..de1322a 100644 --- a/packages/backend/src/cacheService.ts +++ b/packages/backend/src/cacheService.ts @@ -4,38 +4,40 @@ import Keyv from 'keyv'; import KeyvPostgres from '@keyv/postgres'; - -const POSTGRES_HOST = process.env.POSTGRES_HOST; -const POSTGRES_PORT = process.env.POSTGRES_PORT; -const POSTGRES_USER = process.env.POSTGRES_USER; -const POSTGRES_PASSWORD = process.env.POSTGRES_PASSWORD; -const POSTGRES_DB = - process.env.POSTGRES_DB || 'backstage_plugin_tibco_hub_cache'; +import { Knex } from 'knex'; export class KeyvStore { public static keyv: Keyv; public static keyvMemory: Keyv; - public static initialize() { - if ( - !( - POSTGRES_HOST && - POSTGRES_PORT && - POSTGRES_USER && - POSTGRES_PASSWORD && - POSTGRES_DB - ) - ) { - throw new Error('Missing POSTGRES configurations required for Keyv'); + public static initialize(knex: Knex, PLUGIN_ID: string) { + if (knex.client.driverName === 'pg') { + const cfg = knex.client.config.connection; + const connectionString = + typeof cfg === 'string' + ? cfg + : `postgres://${cfg.user}:${cfg.password}@${cfg.host}:${ + cfg.port ?? 5432 + }${cfg.database ? `/${cfg.database}` : ''}`; + let schema = 'public'; + if (typeof cfg !== 'string' && !cfg.database) { + schema = PLUGIN_ID; + } + KeyvStore.keyv = new Keyv( + new KeyvPostgres({ + uri: connectionString, + schema, + }), + ); + } else { + KeyvStore.keyv = new Keyv(); } - KeyvStore.keyv = new Keyv( - new KeyvPostgres( - `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}`, - ), - ); KeyvStore.keyvMemory = new Keyv(); KeyvStore.keyv.on('error', err => { throw new Error(`Error while initializing KeyvStore ${err as Error}`); }); + KeyvStore.keyv.on('error', err => { + throw new Error(`Error while initializing KeyvStore ${err as Error}`); + }); KeyvStore.keyvMemory.on('error', err => { throw new Error( `Error while initializing in memory KeyvStore ${err as Error}`, diff --git a/yarn.lock b/yarn.lock index 76d47f5..c69dfb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15659,6 +15659,17 @@ __metadata: languageName: node linkType: hard +"@types/pg@npm:^8.11.3": + version: 8.15.6 + resolution: "@types/pg@npm:8.15.6" + dependencies: + "@types/node": "npm:*" + pg-protocol: "npm:*" + pg-types: "npm:^2.2.0" + checksum: 10c0/7f93f83a4da0dc6133918f824d826fa34e78fb8cf86392d28a0e095c836c6910c014ced5d4b364d83e8485a65ce369adeb9663b14ba301241d4c0f80073007f3 + languageName: node + linkType: hard + "@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.3": version: 15.7.15 resolution: "@types/prop-types@npm:15.7.15" @@ -17671,6 +17682,7 @@ __metadata: "@internal/plugin-scaffolder-backend-module-metrics-api": "workspace:^" "@internal/plugin-scaffolder-backend-module-tibco-git-repositories": "workspace:^" "@keyv/postgres": "npm:^2.1.7" + "@types/pg": "npm:^8.11.3" app: "link:../app" better-sqlite3: "npm:^9.0.0" cookie-parser: "npm:^1.4.7" @@ -17680,6 +17692,7 @@ __metadata: global-agent: "npm:^3.0.0" jwt-decode: "npm:^3.1.2" keyv: "npm:^5.5.0" + knex: "npm:^3.1.0" node-gyp: "npm:^10.0.0" openid-client: "npm:^5.5.0" pg: "npm:^8.11.3" @@ -29803,14 +29816,14 @@ __metadata: languageName: node linkType: hard -"pg-protocol@npm:^1.10.3": +"pg-protocol@npm:*, pg-protocol@npm:^1.10.3": version: 1.10.3 resolution: "pg-protocol@npm:1.10.3" checksum: 10c0/f7ef54708c93ee6d271e37678296fc5097e4337fca91a88a3d99359b78633dbdbf6e983f0adb34b7cdd261b7ec7266deb20c3233bf3dfdb498b3e1098e8750b9 languageName: node linkType: hard -"pg-types@npm:2.2.0": +"pg-types@npm:2.2.0, pg-types@npm:^2.2.0": version: 2.2.0 resolution: "pg-types@npm:2.2.0" dependencies: From 6d651431c6178a6bf9eab471af393cb77115f2cb Mon Sep 17 00:00:00 2001 From: subrat gantayat Date: Sat, 15 Nov 2025 00:15:29 +0530 Subject: [PATCH 2/3] Reused the variable PLUGIN_ID --- packages/backend/src/cachePlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/cachePlugin.ts b/packages/backend/src/cachePlugin.ts index 2659fa8..bc6a3d4 100644 --- a/packages/backend/src/cachePlugin.ts +++ b/packages/backend/src/cachePlugin.ts @@ -12,7 +12,7 @@ import { Knex } from 'knex'; const PLUGIN_ID: string = 'tibco_hub_cache'; export default createBackendPlugin({ - pluginId: 'tibco_hub_cache', + pluginId: PLUGIN_ID, register(env) { env.registerInit({ deps: { From 77a69ec0e8f25b46c241e827b99276a30e3f4cca Mon Sep 17 00:00:00 2001 From: subrat gantayat Date: Mon, 17 Nov 2025 18:12:17 +0530 Subject: [PATCH 3/3] Resolved the issue where the tables were created in public schema in case of pluginDivisionMode schema and database is passed. --- packages/backend/src/cachePlugin.ts | 8 ++++++-- packages/backend/src/cacheService.ts | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/cachePlugin.ts b/packages/backend/src/cachePlugin.ts index bc6a3d4..0230bbc 100644 --- a/packages/backend/src/cachePlugin.ts +++ b/packages/backend/src/cachePlugin.ts @@ -17,10 +17,14 @@ export default createBackendPlugin({ env.registerInit({ deps: { database: coreServices.database, + config: coreServices.rootConfig, }, - async init({ database }) { + async init({ database, config }) { const knex: Knex = await database.getClient(); - KeyvStore.initialize(knex, PLUGIN_ID); + const pluginDivisionMode: string = + config.getOptionalString('backend.database.pluginDivisionMode') || + 'database'; + KeyvStore.initialize(knex, pluginDivisionMode, PLUGIN_ID); await KeyvStore.keyv.clear(); }, }); diff --git a/packages/backend/src/cacheService.ts b/packages/backend/src/cacheService.ts index de1322a..8d45f95 100644 --- a/packages/backend/src/cacheService.ts +++ b/packages/backend/src/cacheService.ts @@ -9,7 +9,11 @@ import { Knex } from 'knex'; export class KeyvStore { public static keyv: Keyv; public static keyvMemory: Keyv; - public static initialize(knex: Knex, PLUGIN_ID: string) { + public static initialize( + knex: Knex, + pluginDivisionMode: string, + PLUGIN_ID: string, + ) { if (knex.client.driverName === 'pg') { const cfg = knex.client.config.connection; const connectionString = @@ -19,7 +23,7 @@ export class KeyvStore { cfg.port ?? 5432 }${cfg.database ? `/${cfg.database}` : ''}`; let schema = 'public'; - if (typeof cfg !== 'string' && !cfg.database) { + if (typeof cfg !== 'string' && pluginDivisionMode !== 'database') { schema = PLUGIN_ID; } KeyvStore.keyv = new Keyv(