Skip to content

Commit cc322ec

Browse files
committed
[prebuilds] no prebuilds for inactive repos
1 parent 3939796 commit cc322ec

File tree

5 files changed

+101
-1
lines changed

5 files changed

+101
-1
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class CloneUrlIndexed1652365883273 implements MigrationInterface {
4+
public async up(queryRunner: QueryRunner): Promise<void> {
5+
queryRunner.query(`
6+
ALTER TABLE
7+
d_b_workspace
8+
ADD COLUMN
9+
cloneURL VARCHAR(50)
10+
GENERATED ALWAYS AS (
11+
context ->> \"$.repository.cloneUrl\"
12+
);
13+
CREATE INDEX d_b_workspace_cloneURL_idx ON d_b_workspace (cloneURL);
14+
`);
15+
}
16+
17+
public async down(queryRunner: QueryRunner): Promise<void> {}
18+
}

components/gitpod-db/src/typeorm/workspace-db-impl.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,22 @@ export abstract class AbstractTypeORMWorkspaceDBImpl implements WorkspaceDB {
356356
return workspaceRepo.find({ ownerId: userId });
357357
}
358358

359+
public async getWorkspaceCountByCloneURL(
360+
cloneURL: string,
361+
sinceLastDays: number = 7,
362+
type: string = "regular",
363+
): Promise<number> {
364+
const workspaceRepo = await this.getWorkspaceRepo();
365+
const since = new Date();
366+
since.setDate(since.getDate() - sinceLastDays);
367+
return workspaceRepo
368+
.createQueryBuilder("ws")
369+
.where('cloneURL" = :cloneURL', { cloneURL })
370+
.andWhere("creationTime > :since", { since: since.toISOString() })
371+
.andWhere("type = :type", { type })
372+
.getCount();
373+
}
374+
359375
public async findCurrentInstance(workspaceId: string): Promise<MaybeWorkspaceInstance> {
360376
const workspaceInstanceRepo = await this.getWorkspaceInstanceRepo();
361377
const qb = workspaceInstanceRepo

components/gitpod-db/src/workspace-db.spec.db.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const expect = chai.expect;
99
import { suite, test, timeout } from "mocha-typescript";
1010
import { fail } from "assert";
1111

12-
import { WorkspaceInstance, Workspace, PrebuiltWorkspace } from "@gitpod/gitpod-protocol";
12+
import { WorkspaceInstance, Workspace, PrebuiltWorkspace, CommitContext } from "@gitpod/gitpod-protocol";
1313
import { testContainer } from "./test-container";
1414
import { TypeORMWorkspaceDBImpl } from "./typeorm/workspace-db-impl";
1515
import { TypeORM } from "./typeorm/typeorm";
@@ -539,6 +539,52 @@ class WorkspaceDBSpec {
539539
expect(unabortedCount).to.eq(1);
540540
}
541541

542+
@test(timeout(10000))
543+
public async testGetWorkspaceCountForCloneURL() {
544+
const now = new Date();
545+
const eightDaysAgo = new Date();
546+
eightDaysAgo.setDate(eightDaysAgo.getDate() - 8);
547+
const activeRepo = "http://github.com/myorg/active.git";
548+
const inactiveRepo = "http://github.com/myorg/inactive.git";
549+
await Promise.all([
550+
this.db.store({
551+
id: "12345",
552+
creationTime: eightDaysAgo.toISOString(),
553+
description: "something",
554+
contextURL: "http://github.com/myorg/inactive",
555+
ownerId: "1221423",
556+
context: <CommitContext>{
557+
title: "my title",
558+
repository: {
559+
cloneUrl: inactiveRepo,
560+
},
561+
},
562+
config: {},
563+
type: "regular",
564+
}),
565+
this.db.store({
566+
id: "12346",
567+
creationTime: now.toISOString(),
568+
description: "something",
569+
contextURL: "http://github.com/myorg/active",
570+
ownerId: "1221423",
571+
context: <CommitContext>{
572+
title: "my title",
573+
repository: {
574+
cloneUrl: activeRepo,
575+
},
576+
},
577+
config: {},
578+
type: "regular",
579+
}),
580+
]);
581+
582+
const inactiveCount = await this.db.getWorkspaceCountByCloneURL(inactiveRepo, 7, "regular");
583+
expect(inactiveCount).to.eq(0, "there should be no regular workspaces in the past 7 days");
584+
const activeCount = await this.db.getWorkspaceCountByCloneURL(activeRepo, 7, "regular");
585+
expect(activeCount).to.eq(1, "there should be exactly one regular workspace");
586+
}
587+
542588
private async storePrebuiltWorkspace(pws: PrebuiltWorkspace) {
543589
// store the creationTime directly, before it is modified by the store function in the ORM layer
544590
const creationTime = pws.creationTime;

components/gitpod-db/src/workspace-db.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export interface WorkspaceDB {
125125
findInstancesByPhaseAndRegion(phase: string, region: string): Promise<WorkspaceInstance[]>;
126126

127127
getWorkspaceCount(type?: String): Promise<Number>;
128+
getWorkspaceCountByCloneURL(cloneURL: string, sinceLastDays?: number, type?: string): Promise<number>;
128129
getInstanceCount(type?: string): Promise<number>;
129130

130131
findAllWorkspaceInstances(

components/server/ee/src/prebuilds/prebuild-manager.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ export class PrebuildManager {
195195
prebuild.error =
196196
"Project is inactive. Please start a new workspace for this project to re-enable prebuilds.";
197197
await this.workspaceDB.trace({ span }).storePrebuiltWorkspace(prebuild);
198+
} else if (!project && (await this.shouldSkipInactiveRepository({ span }, cloneURL))) {
199+
prebuild.state = "aborted";
200+
prebuild.error =
201+
"Repository is inactive. Please create a project for this repository to re-enable prebuilds.";
202+
await this.workspaceDB.trace({ span }).storePrebuiltWorkspace(prebuild);
198203
} else {
199204
span.setTag("starting", true);
200205
const projectEnvVars = await projectEnvVarsPromise;
@@ -356,4 +361,18 @@ export class PrebuildManager {
356361
const inactiveProjectTime = 1000 * 60 * 60 * 24 * 7 * 1; // 1 week
357362
return now - lastUse > inactiveProjectTime;
358363
}
364+
365+
private async shouldSkipInactiveRepository(ctx: TraceContext, cloneURL: string): Promise<boolean> {
366+
const span = TraceContext.startSpan("shouldSkipInactiveRepository", ctx);
367+
try {
368+
return (
369+
(await this.workspaceDB
370+
.trace({ span })
371+
.getWorkspaceCountByCloneURL(cloneURL, 7 /* last week */, "regular")) === 0
372+
);
373+
} catch (error) {
374+
log.error("cannot compute activity for repository", { cloneURL }, error);
375+
return false;
376+
}
377+
}
359378
}

0 commit comments

Comments
 (0)