Skip to content

Commit 3755662

Browse files
committed
[server] Merge WorkspaceDeletionService into WorkspaceGC
1 parent 8da43bb commit 3755662

File tree

3 files changed

+91
-114
lines changed

3 files changed

+91
-114
lines changed

components/server/src/container-module.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ import { ReferrerPrefixParser } from "./workspace/referrer-prefix-context-parser
118118
import { SnapshotContextParser } from "./workspace/snapshot-context-parser";
119119
import { SnapshotService } from "./workspace/snapshot-service";
120120
import { WorkspaceClusterImagebuilderClientProvider } from "./workspace/workspace-cluster-imagebuilder-client-provider";
121-
import { WorkspaceDeletionService } from "./workspace/workspace-deletion-service";
122121
import { WorkspaceDownloadService } from "./workspace/workspace-download-service";
123122
import { WorkspaceFactory } from "./workspace/workspace-factory";
124123
import { WorkspaceStarter } from "./workspace/workspace-starter";
@@ -162,7 +161,6 @@ export const productionContainerModule = new ContainerModule(
162161
bind(SnapshotService).toSelf().inSingletonScope();
163162
bind(WorkspaceService).toSelf().inSingletonScope();
164163
bind(WorkspaceFactory).toSelf().inSingletonScope();
165-
bind(WorkspaceDeletionService).toSelf().inSingletonScope();
166164
bind(WorkspaceStarter).toSelf().inSingletonScope();
167165
bind(ImageSourceProvider).toSelf().inSingletonScope();
168166

components/server/src/jobs/workspace-gc.ts

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,19 @@
66

77
import { injectable, inject, postConstruct } from "inversify";
88
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
9-
import { WorkspaceDeletionService } from "../workspace/workspace-deletion-service";
109
import * as opentracing from "opentracing";
11-
import { TracedWorkspaceDB, DBWithTracing, WorkspaceDB } from "@gitpod/gitpod-db/lib";
10+
import {
11+
TracedWorkspaceDB,
12+
DBWithTracing,
13+
WorkspaceDB,
14+
WorkspaceAndOwner,
15+
WorkspaceOwnerAndSoftDeleted,
16+
} from "@gitpod/gitpod-db/lib";
1217
import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing";
1318
import { Config } from "../config";
1419
import { Job } from "./runner";
1520
import { WorkspaceService } from "../workspace/workspace-service";
21+
import { StorageClient } from "../storage/storage-client";
1622

1723
/**
1824
* The WorkspaceGarbageCollector has two tasks:
@@ -21,10 +27,12 @@ import { WorkspaceService } from "../workspace/workspace-service";
2127
*/
2228
@injectable()
2329
export class WorkspaceGarbageCollector implements Job {
24-
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService;
25-
@inject(WorkspaceDeletionService) protected readonly deletionService: WorkspaceDeletionService;
26-
@inject(TracedWorkspaceDB) protected readonly workspaceDB: DBWithTracing<WorkspaceDB>;
27-
@inject(Config) protected readonly config: Config;
30+
constructor(
31+
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService,
32+
@inject(StorageClient) protected readonly storageClient: StorageClient,
33+
@inject(TracedWorkspaceDB) protected readonly workspaceDB: DBWithTracing<WorkspaceDB>,
34+
@inject(Config) protected readonly config: Config,
35+
) {}
2836

2937
public name = "workspace-gc";
3038
public frequencyMs: number;
@@ -55,7 +63,7 @@ export class WorkspaceGarbageCollector implements Job {
5563
/**
5664
* Marks old, unused workspaces as softDeleted
5765
*/
58-
protected async softDeleteOldWorkspaces() {
66+
private async softDeleteOldWorkspaces() {
5967
if (Date.now() < this.config.workspaceGarbageCollection.startDate) {
6068
log.info("workspace-gc: garbage collection not yet active.");
6169
return;
@@ -89,7 +97,7 @@ export class WorkspaceGarbageCollector implements Job {
8997
}
9098
}
9199

92-
protected async deleteWorkspaceContentAfterRetentionPeriod() {
100+
private async deleteWorkspaceContentAfterRetentionPeriod() {
93101
const span = opentracing.globalTracer().startSpan("deleteWorkspaceContentAfterRetentionPeriod");
94102
try {
95103
const workspaces = await this.workspaceDB
@@ -98,9 +106,7 @@ export class WorkspaceGarbageCollector implements Job {
98106
this.config.workspaceGarbageCollection.contentRetentionPeriodDays,
99107
this.config.workspaceGarbageCollection.contentChunkLimit,
100108
);
101-
const deletes = await Promise.all(
102-
workspaces.map((ws) => this.deletionService.garbageCollectWorkspace({ span }, ws)),
103-
);
109+
const deletes = await Promise.all(workspaces.map((ws) => this.garbageCollectWorkspace({ span }, ws)));
104110

105111
log.info(`workspace-gc: successfully deleted the content of ${deletes.length} workspaces`);
106112
span.addTags({ nrOfCollectedWorkspaces: deletes.length });
@@ -115,7 +121,7 @@ export class WorkspaceGarbageCollector implements Job {
115121
/**
116122
* This method is meant to purge all traces of a Workspace and it's WorkspaceInstances from the DB
117123
*/
118-
protected async purgeWorkspacesAfterPurgeRetentionPeriod() {
124+
private async purgeWorkspacesAfterPurgeRetentionPeriod() {
119125
const span = opentracing.globalTracer().startSpan("purgeWorkspacesAfterPurgeRetentionPeriod");
120126
try {
121127
const now = new Date();
@@ -144,7 +150,7 @@ export class WorkspaceGarbageCollector implements Job {
144150
}
145151
}
146152

147-
protected async deleteOldPrebuilds() {
153+
private async deleteOldPrebuilds() {
148154
const span = opentracing.globalTracer().startSpan("deleteOldPrebuilds");
149155
try {
150156
const workspaces = await this.workspaceDB
@@ -153,9 +159,7 @@ export class WorkspaceGarbageCollector implements Job {
153159
this.config.workspaceGarbageCollection.minAgePrebuildDays,
154160
this.config.workspaceGarbageCollection.chunkLimit,
155161
);
156-
const deletes = await Promise.all(
157-
workspaces.map((ws) => this.deletionService.garbageCollectPrebuild({ span }, ws)),
158-
);
162+
const deletes = await Promise.all(workspaces.map((ws) => this.garbageCollectPrebuild({ span }, ws)));
159163

160164
log.info(`workspace-gc: successfully deleted ${deletes.length} prebuilds`);
161165
span.addTags({ nrOfCollectedPrebuilds: deletes.length });
@@ -166,4 +170,75 @@ export class WorkspaceGarbageCollector implements Job {
166170
span.finish();
167171
}
168172
}
173+
174+
/**
175+
* This method garbageCollects a workspace. It deletes its contents and sets the workspaces 'contentDeletedTime'
176+
* @param ctx
177+
* @param ws
178+
*/
179+
private async garbageCollectWorkspace(ctx: TraceContext, ws: WorkspaceOwnerAndSoftDeleted): Promise<boolean> {
180+
const span = TraceContext.startSpan("garbageCollectWorkspace", ctx);
181+
182+
try {
183+
const successfulDeleted = await this.deleteWorkspaceStorage({ span }, ws, true);
184+
await this.workspaceDB
185+
.trace({ span })
186+
.updatePartial(ws.id, { contentDeletedTime: new Date().toISOString() });
187+
return successfulDeleted;
188+
} catch (err) {
189+
TraceContext.setError({ span }, err);
190+
throw err;
191+
} finally {
192+
span.finish();
193+
}
194+
}
195+
196+
/**
197+
* @param ctx
198+
* @param wsAndOwner
199+
*/
200+
private async garbageCollectPrebuild(ctx: TraceContext, ws: WorkspaceAndOwner): Promise<boolean> {
201+
const span = TraceContext.startSpan("garbageCollectPrebuild", ctx);
202+
203+
try {
204+
const successfulDeleted = await this.deleteWorkspaceStorage({ span }, ws, true);
205+
const now = new Date().toISOString();
206+
// Note: soft & content deletion happens at the same time, because prebuilds are reproducible so there's no need for the extra time span.
207+
await this.workspaceDB.trace({ span }).updatePartial(ws.id, {
208+
contentDeletedTime: now,
209+
softDeletedTime: now,
210+
softDeleted: "gc",
211+
});
212+
return successfulDeleted;
213+
} catch (err) {
214+
TraceContext.setError({ span }, err);
215+
throw err;
216+
} finally {
217+
span.finish();
218+
}
219+
}
220+
221+
/**
222+
* Performs the actual deletion of a workspace's backups (and optionally, snapshots). It:
223+
* - throws an error if something went wrong during deletion
224+
* - returns true in case of successful deletion
225+
* @param ws
226+
* @param includeSnapshots
227+
*/
228+
private async deleteWorkspaceStorage(
229+
ctx: TraceContext,
230+
ws: WorkspaceAndOwner,
231+
includeSnapshots: boolean,
232+
): Promise<boolean> {
233+
const span = TraceContext.startSpan("deleteWorkspaceStorage", ctx);
234+
try {
235+
await this.storageClient.deleteWorkspaceBackups(ws.ownerId, ws.id, includeSnapshots);
236+
} catch (err) {
237+
TraceContext.setError({ span }, err);
238+
throw err;
239+
} finally {
240+
span.finish();
241+
}
242+
return true;
243+
}
169244
}

components/server/src/workspace/workspace-deletion-service.ts

Lines changed: 0 additions & 96 deletions
This file was deleted.

0 commit comments

Comments
 (0)