From b77d70585ebe8968eb573e90ef22d81f4da0e1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Jedlicska?= <57442769+gjedlicska@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:18:28 +0100 Subject: [PATCH] fix(redis): make redis client singleton from a module (#3469) * fix(redis): make redis client singleton from a module * fix(projectDownload): pass region key properly --- .../automate/graph/resolvers/automate.ts | 2 +- .../modules/automate/rest/authGithubApp.ts | 2 +- .../automate/tests/automations.spec.ts | 2 +- .../modules/cli/commands/download/project.ts | 7 +++-- packages/server/modules/core/index.ts | 27 +++---------------- .../cross-server-sync/domain/operations.ts | 1 + .../cross-server-sync/services/project.ts | 5 ++-- .../server/modules/multiregion/dbSelector.ts | 2 +- packages/server/modules/shared/redis/redis.ts | 8 ++++++ .../server/modules/workspaces/rest/sso.ts | 2 +- 10 files changed, 26 insertions(+), 32 deletions(-) diff --git a/packages/server/modules/automate/graph/resolvers/automate.ts b/packages/server/modules/automate/graph/resolvers/automate.ts index afc1a5400..b0c1b2ab7 100644 --- a/packages/server/modules/automate/graph/resolvers/automate.ts +++ b/packages/server/modules/automate/graph/resolvers/automate.ts @@ -52,7 +52,7 @@ import { Resolvers, AutomateRunTriggerType } from '@/modules/core/graph/generated/graphql' -import { getGenericRedis } from '@/modules/core/index' +import { getGenericRedis } from '@/modules/shared/redis/redis' import { createAutomation as clientCreateAutomation } from '@/modules/automate/clients/executionEngine' import { Automate, Roles, isNullOrUndefined, isNonNullable } from '@speckle/shared' import { getFeatureFlags, getServerOrigin } from '@/modules/shared/helpers/envHelper' diff --git a/packages/server/modules/automate/rest/authGithubApp.ts b/packages/server/modules/automate/rest/authGithubApp.ts index 054015a31..abf1c99bf 100644 --- a/packages/server/modules/automate/rest/authGithubApp.ts +++ b/packages/server/modules/automate/rest/authGithubApp.ts @@ -4,7 +4,7 @@ import { handleAutomateFunctionCreatorAuthCallbackFactory, startAutomateFunctionCreatorAuthFactory } from '@/modules/automate/services/functionManagement' -import { getGenericRedis } from '@/modules/core' +import { getGenericRedis } from '@/modules/shared/redis/redis' import { corsMiddleware } from '@/modules/core/configs/cors' import { validateScope, validateServerRoleBuilderFactory } from '@/modules/shared/authz' import { authMiddlewareCreator } from '@/modules/shared/middleware' diff --git a/packages/server/modules/automate/tests/automations.spec.ts b/packages/server/modules/automate/tests/automations.spec.ts index d13a26693..c5edd6bb5 100644 --- a/packages/server/modules/automate/tests/automations.spec.ts +++ b/packages/server/modules/automate/tests/automations.spec.ts @@ -11,7 +11,7 @@ import { AuthCodePayloadAction, createStoredAuthCodeFactory } from '@/modules/automate/services/authCode' -import { getGenericRedis } from '@/modules/core' +import { getGenericRedis } from '@/modules/shared/redis/redis' import { ProjectAutomationRevisionCreateInput } from '@/modules/core/graph/generated/graphql' import { BranchRecord } from '@/modules/core/helpers/types' import { getLatestStreamBranchFactory } from '@/modules/core/repositories/branches' diff --git a/packages/server/modules/cli/commands/download/project.ts b/packages/server/modules/cli/commands/download/project.ts index d149a0305..25474ada5 100644 --- a/packages/server/modules/cli/commands/download/project.ts +++ b/packages/server/modules/cli/commands/download/project.ts @@ -118,6 +118,7 @@ const command: CommandModule< handler: async (argv) => { let projectDb = db console.log(argv) + let regionKey: string | undefined = undefined if (argv.workspaceId) { await authorizeResolver( argv.authorId, @@ -128,7 +129,9 @@ const command: CommandModule< const workspaceDefaultRegion = await getDefaultRegionFactory({ db })({ workspaceId: argv.workspaceId }) - const regionKey = workspaceDefaultRegion?.key + regionKey = workspaceDefaultRegion?.key + console.log(workspaceDefaultRegion) + console.log(regionKey) projectDb = await getDb({ regionKey }) } const getStream = getStreamFactory({ db: projectDb }) @@ -253,7 +256,7 @@ const command: CommandModule< }) }) }) - await downloadProject(argv, { logger: cliLogger }) + await downloadProject({ ...argv, regionKey }, { logger: cliLogger }) } } diff --git a/packages/server/modules/core/index.ts b/packages/server/modules/core/index.ts index 58f100cdc..0796fbad1 100644 --- a/packages/server/modules/core/index.ts +++ b/packages/server/modules/core/index.ts @@ -4,7 +4,7 @@ import { shutdownResultListener } from '@/modules/core/utils/dbNotificationListener' import * as mp from '@/modules/shared/utils/mixpanel' -import { Optional, SpeckleModule } from '@/modules/shared/helpers/typeHelper' +import { SpeckleModule } from '@/modules/shared/helpers/typeHelper' import staticRest from '@/modules/core/rest/static' import uploadRest from '@/modules/core/rest/upload' @@ -13,19 +13,12 @@ import diffUpload from '@/modules/core/rest/diffUpload' import diffDownload from '@/modules/core/rest/diffDownload' import scopes from '@/modules/core/scopes' import roles from '@/modules/core/roles' -import Redis from 'ioredis' -import { createRedisClient } from '@/modules/shared/redis/redis' -import { getRedisUrl } from '@/modules/shared/helpers/envHelper' -import { UninitializedResourceAccessError } from '@/modules/shared/errors' +import { getGenericRedis } from '@/modules/shared/redis/redis' import { registerOrUpdateScopeFactory } from '@/modules/shared/repositories/scopes' import db from '@/db/knex' import { registerOrUpdateRole } from '@/modules/shared/repositories/roles' -let genericRedisClient: Optional = undefined - -const coreModule: SpeckleModule<{ - getGenericRedis: () => Redis -}> = { +const coreModule: SpeckleModule = { async init(app, isInitial) { moduleLogger.info('💥 Init core module') @@ -60,24 +53,12 @@ const coreModule: SpeckleModule<{ mp.initialize() // Generic redis client - genericRedisClient = createRedisClient(getRedisUrl(), {}) } }, async shutdown() { await shutdownResultListener() - if (genericRedisClient) { - await genericRedisClient.quit() - } - }, - /** - * A general purpose redis client that can be used after safely all modules are initialized - */ - getGenericRedis() { - if (!genericRedisClient) { - throw new UninitializedResourceAccessError('Generic redis client not initialized') - } - return genericRedisClient + await getGenericRedis().quit() } } diff --git a/packages/server/modules/cross-server-sync/domain/operations.ts b/packages/server/modules/cross-server-sync/domain/operations.ts index efdb4f699..137578cd0 100644 --- a/packages/server/modules/cross-server-sync/domain/operations.ts +++ b/packages/server/modules/cross-server-sync/domain/operations.ts @@ -60,6 +60,7 @@ export type DownloadProject = ( * The author needs to be member of the workspace */ workspaceId?: string + regionKey?: string }, options?: Partial<{ logger: Logger diff --git a/packages/server/modules/cross-server-sync/services/project.ts b/packages/server/modules/cross-server-sync/services/project.ts index b23265c15..545d8dff0 100644 --- a/packages/server/modules/cross-server-sync/services/project.ts +++ b/packages/server/modules/cross-server-sync/services/project.ts @@ -203,7 +203,7 @@ type DownloadProjectDeps = { export const downloadProjectFactory = (deps: DownloadProjectDeps): DownloadProject => async (params, options) => { - const { projectUrl, authorId, syncComments, token, workspaceId } = params + const { projectUrl, authorId, syncComments, token, workspaceId, regionKey } = params const { logger = crossServerSyncLogger } = options || {} logger.info(`Project download started at: ${new Date().toISOString()}`) @@ -222,7 +222,8 @@ export const downloadProjectFactory = const project = await deps.createNewProject({ ...projectInfo.projectInfo, workspaceId, - ownerId: localResources.user.id + ownerId: localResources.user.id, + regionKey }) await importVersionsFactory(deps)({ diff --git a/packages/server/modules/multiregion/dbSelector.ts b/packages/server/modules/multiregion/dbSelector.ts index 18f2af125..dcc645273 100644 --- a/packages/server/modules/multiregion/dbSelector.ts +++ b/packages/server/modules/multiregion/dbSelector.ts @@ -12,7 +12,7 @@ import { getProjectRegionKeyFactory, GetRegionDb } from '@/modules/multiregion/services/projectRegion' -import { getGenericRedis } from '@/modules/core' +import { getGenericRedis } from '@/modules/shared/redis/redis' import knex, { Knex } from 'knex' import { getRegionFactory, getRegionsFactory } from '@/modules/multiregion/repositories' import { MisconfiguredEnvironmentError } from '@/modules/shared/errors' diff --git a/packages/server/modules/shared/redis/redis.ts b/packages/server/modules/shared/redis/redis.ts index a65e0990e..285b455e4 100644 --- a/packages/server/modules/shared/redis/redis.ts +++ b/packages/server/modules/shared/redis/redis.ts @@ -4,6 +4,7 @@ import { EnvironmentResourceError, MisconfiguredEnvironmentError } from '@/modules/shared/errors' +import { getRedisUrl } from '@/modules/shared/helpers/envHelper' export function createRedisClient(redisUrl: string, redisOptions: RedisOptions): Redis { let redisClient: Redis @@ -26,3 +27,10 @@ export function createRedisClient(redisUrl: string, redisOptions: RedisOptions): return redisClient } + +let redisClient: Redis | undefined = undefined + +export const getGenericRedis = (): Redis => { + if (!redisClient) redisClient = createRedisClient(getRedisUrl(), {}) + return redisClient +} diff --git a/packages/server/modules/workspaces/rest/sso.ts b/packages/server/modules/workspaces/rest/sso.ts index f4ab4eebd..c4b8a351b 100644 --- a/packages/server/modules/workspaces/rest/sso.ts +++ b/packages/server/modules/workspaces/rest/sso.ts @@ -24,7 +24,7 @@ import { upsertUserSsoSessionFactory, getWorkspaceSsoProviderFactory } from '@/modules/workspaces/repositories/sso' -import { getGenericRedis } from '@/modules/core' +import { getGenericRedis } from '@/modules/shared/redis/redis' import { generators, UserinfoResponse } from 'openid-client' import { oidcProvider } from '@/modules/workspaces/domain/sso/models' import {