diff --git a/packages/backend-core/src/objectStore/objectStore.ts b/packages/backend-core/src/objectStore/objectStore.ts index 064cc630d8..33b42e0131 100644 --- a/packages/backend-core/src/objectStore/objectStore.ts +++ b/packages/backend-core/src/objectStore/objectStore.ts @@ -478,7 +478,7 @@ export async function deleteFolder( if (existingObjectsResponse.Contents?.length === 0) { return } - const deleteParams: any = { + const deleteParams: { Bucket: string; Delete: { Objects: any[] } } = { Bucket: bucketName, Delete: { Objects: [], @@ -489,10 +489,12 @@ export async function deleteFolder( deleteParams.Delete.Objects.push({ Key: content.Key }) }) - const deleteResponse = await client.deleteObjects(deleteParams) - // can only empty 1000 items at once - if (deleteResponse.Deleted?.length === 1000) { - return deleteFolder(bucketName, folder) + if (deleteParams.Delete.Objects.length) { + const deleteResponse = await client.deleteObjects(deleteParams) + // can only empty 1000 items at once + if (deleteResponse.Deleted?.length === 1000) { + return deleteFolder(bucketName, folder) + } } } diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index a3b08b5ff9..867eb2881b 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -635,6 +635,11 @@ async function unpublishApp(ctx: UserCtx) { return result } +async function invalidateAppCache(appId: string) { + await cache.app.invalidateAppMetadata(dbCore.getDevAppID(appId)) + await cache.app.invalidateAppMetadata(dbCore.getProdAppID(appId)) +} + async function destroyApp(ctx: UserCtx) { let appId = ctx.params.appId appId = dbCore.getProdAppID(appId) @@ -654,17 +659,21 @@ async function destroyApp(ctx: UserCtx) { await quotas.removeApp() await events.app.deleted(app) - if (!env.isTest()) { + if (!env.USE_LOCAL_COMPONENT_LIBS) { await deleteAppFiles(appId) } await removeAppFromUserRoles(ctx, appId) - await cache.app.invalidateAppMetadata(devAppId) + await invalidateAppCache(appId) return result } async function preDestroyApp(ctx: UserCtx) { - const { rows } = await getUniqueRows([ctx.params.appId]) + // invalidate the cache immediately in-case they are leading to + // zombie appearing apps + const appId = ctx.params.appId + await invalidateAppCache(appId) + const { rows } = await getUniqueRows([appId]) ctx.rowCount = rows.length } diff --git a/packages/server/src/api/routes/tests/application.spec.ts b/packages/server/src/api/routes/tests/application.spec.ts index 9480593c2a..cff205bbfa 100644 --- a/packages/server/src/api/routes/tests/application.spec.ts +++ b/packages/server/src/api/routes/tests/application.spec.ts @@ -1,4 +1,5 @@ import { DEFAULT_TABLES } from "../../../db/defaultData/datasource_bb_default" +import { setEnv } from "../../../environment" jest.mock("../../../utilities/redis", () => ({ init: jest.fn(), @@ -27,10 +28,16 @@ import path from "path" describe("/applications", () => { let config = setup.getConfig() - let app: App + let app: App, cleanup: () => void - afterAll(setup.afterAll) - beforeAll(async () => await config.init()) + afterAll(() => { + setup.afterAll() + cleanup() + }) + beforeAll(async () => { + cleanup = setEnv({ USE_LOCAL_COMPONENT_LIBS: "0" }) + await config.init() + }) beforeEach(async () => { app = await config.api.application.create({ name: utils.newid() })