diff --git a/packages/backend/src/api.ts b/packages/backend/src/api.ts index 7b5cfc895..3cb61ebb8 100644 --- a/packages/backend/src/api.ts +++ b/packages/backend/src/api.ts @@ -18,7 +18,7 @@ import { SINGLE_TENANT_ORG_ID } from './constants.js'; import { isGitHubRateLimitError, isNotFound } from './errors.js'; import { PromClient } from './promClient.js'; import { createGitHubRepoRecord } from './repoCompileUtils.js'; -import type { JobManager } from './types.js'; +import type { JobManager, Settings } from './types.js'; const logger = createLogger('api'); @@ -35,6 +35,7 @@ export class Api { private prisma: PrismaClient, private jobManager: JobManager, redis: Redis, + private settings: Settings, ) { const app = express(); app.use(express.json()); @@ -138,14 +139,11 @@ export class Api { create: record, }); - const jobId = await this.jobManager.trigger( - 'repo-index', - { - repoId: repo.id, - type: RepoIndexingJobType.INDEX, - }, - { priority: JOB_PRIORITIES.INTERACTIVE }, - ); + const jobId = await scheduleAndTriggerRepoIndexing({ + jobManager: this.jobManager, + repoId: repo.id, + reindexIntervalMs: this.settings.reindexIntervalMs, + }); res.status(200).json({ jobId, repoId: repo.id }); } @@ -162,3 +160,33 @@ export class Api { }); } } + +const scheduleAndTriggerRepoIndexing = async ({ + jobManager, + repoId, + reindexIntervalMs, +}: { + jobManager: JobManager; + repoId: number; + reindexIntervalMs: number; +}): Promise => { + await jobManager.upsertJobScheduler( + "repo-index", + `repo-index-v1-${repoId}`, + reindexIntervalMs, + { + repoId, + type: RepoIndexingJobType.INDEX, + }, + { priority: JOB_PRIORITIES.SCHEDULED }, + ); + + return jobManager.trigger( + "repo-index", + { + repoId, + type: RepoIndexingJobType.INDEX, + }, + { priority: JOB_PRIORITIES.INTERACTIVE }, + ); +}; diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 427e9aab7..1974421e6 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -84,7 +84,7 @@ jobManager.register(repoPermissionSyncWorkload); jobManager.register(attachmentPruneWorkload); jobManager.register(auditLogPruneWorkload); -const api = new Api(promClient, prisma, jobManager, redis); +const api = new Api(promClient, prisma, jobManager, redis, settings); await cleanupOrphanedRepoResources(prisma); diff --git a/packages/backend/src/reconcileJobSchedulers.test.ts b/packages/backend/src/reconcileJobSchedulers.test.ts index b0f685aa4..223da8506 100644 --- a/packages/backend/src/reconcileJobSchedulers.test.ts +++ b/packages/backend/src/reconcileJobSchedulers.test.ts @@ -71,9 +71,16 @@ describe("reconcileJobSchedulers", () => { }); expect(mocks.repoFindMany).toHaveBeenCalledWith({ where: { - connections: { - some: {}, - }, + OR: [ + { + connections: { + some: {}, + }, + }, + { + isAutoCleanupDisabled: true, + }, + ], }, select: { id: true }, }); @@ -205,6 +212,44 @@ describe("reconcileJobSchedulers", () => { ).toBeLessThan(mocks.trigger.mock.invocationCallOrder[0]); }); + test("keeps index schedulers for repos with automatic cleanup disabled", async () => { + mocks.repoFindMany.mockImplementation(async ({ where }) => { + if (where?.isAutoCleanupDisabled === false) { + return []; + } + if (where?.isPublic === false) { + return []; + } + return [{ id: 42 }, { id: 84 }]; + }); + mocks.getJobSchedulerIds.mockImplementation(async (workloadName) => + workloadName === "repo-index" ? ["repo-index-v1-84"] : [], + ); + + await reconcileJobSchedulers({ + db, + jobManager, + settings: { + resyncConnectionIntervalMs: 86_400_000, + reindexIntervalMs: 3_600_000, + userDrivenPermissionSyncIntervalMs: 43_200_000, + repoDrivenPermissionSyncIntervalMs: 21_600_000, + }, + }); + + expect(mocks.upsertJobScheduler).toHaveBeenCalledWith( + "repo-index", + "repo-index-v1-84", + 3_600_000, + { repoId: 84, type: "INDEX" }, + { priority: 10 }, + ); + expect(mocks.removeJobScheduler).not.toHaveBeenCalledWith( + "repo-index", + "repo-index-v1-84", + ); + }); + test("removes permission schedulers when permission syncing is disabled", async () => { isPermissionSyncEnabled.mockResolvedValue(false); mocks.getJobSchedulerIds.mockImplementation(async (workloadName) => { diff --git a/packages/backend/src/reconcileJobSchedulers.ts b/packages/backend/src/reconcileJobSchedulers.ts index 9257fc811..9f21f1d57 100644 --- a/packages/backend/src/reconcileJobSchedulers.ts +++ b/packages/backend/src/reconcileJobSchedulers.ts @@ -56,9 +56,16 @@ export const reconcileJobSchedulers = async ({ }), db.repo.findMany({ where: { - connections: { - some: {}, - }, + OR: [ + { + connections: { + some: {}, + }, + }, + { + isAutoCleanupDisabled: true, + }, + ], }, select: { id: true,