Skip to content

Commit 08a9dc2

Browse files
committed
[server] Merge WorkspaceDeletionService into WorkspaceGC
1 parent 0d36c68 commit 08a9dc2

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,14 +6,20 @@
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";
1621
import { SYSTEM_USER } from "../authorization/authorizer";
22+
import { StorageClient } from "../storage/storage-client";
1723

1824
/**
1925
* The WorkspaceGarbageCollector has two tasks:
@@ -22,10 +28,12 @@ import { SYSTEM_USER } from "../authorization/authorizer";
2228
*/
2329
@injectable()
2430
export class WorkspaceGarbageCollector implements Job {
25-
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService;
26-
@inject(WorkspaceDeletionService) protected readonly deletionService: WorkspaceDeletionService;
27-
@inject(TracedWorkspaceDB) protected readonly workspaceDB: DBWithTracing<WorkspaceDB>;
28-
@inject(Config) protected readonly config: Config;
31+
constructor(
32+
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService,
33+
@inject(StorageClient) protected readonly storageClient: StorageClient,
34+
@inject(TracedWorkspaceDB) protected readonly workspaceDB: DBWithTracing<WorkspaceDB>,
35+
@inject(Config) protected readonly config: Config,
36+
) {}
2937

3038
public name = "workspace-gc";
3139
public frequencyMs: number;
@@ -56,7 +64,7 @@ export class WorkspaceGarbageCollector implements Job {
5664
/**
5765
* Marks old, unused workspaces as softDeleted
5866
*/
59-
protected async softDeleteOldWorkspaces() {
67+
private async softDeleteOldWorkspaces() {
6068
if (Date.now() < this.config.workspaceGarbageCollection.startDate) {
6169
log.info("workspace-gc: garbage collection not yet active.");
6270
return;
@@ -90,7 +98,7 @@ export class WorkspaceGarbageCollector implements Job {
9098
}
9199
}
92100

93-
protected async deleteWorkspaceContentAfterRetentionPeriod() {
101+
private async deleteWorkspaceContentAfterRetentionPeriod() {
94102
const span = opentracing.globalTracer().startSpan("deleteWorkspaceContentAfterRetentionPeriod");
95103
try {
96104
const workspaces = await this.workspaceDB
@@ -99,9 +107,7 @@ export class WorkspaceGarbageCollector implements Job {
99107
this.config.workspaceGarbageCollection.contentRetentionPeriodDays,
100108
this.config.workspaceGarbageCollection.contentChunkLimit,
101109
);
102-
const deletes = await Promise.all(
103-
workspaces.map((ws) => this.deletionService.garbageCollectWorkspace({ span }, ws)),
104-
);
110+
const deletes = await Promise.all(workspaces.map((ws) => this.garbageCollectWorkspace({ span }, ws)));
105111

106112
log.info(`workspace-gc: successfully deleted the content of ${deletes.length} workspaces`);
107113
span.addTags({ nrOfCollectedWorkspaces: deletes.length });
@@ -116,7 +122,7 @@ export class WorkspaceGarbageCollector implements Job {
116122
/**
117123
* This method is meant to purge all traces of a Workspace and it's WorkspaceInstances from the DB
118124
*/
119-
protected async purgeWorkspacesAfterPurgeRetentionPeriod() {
125+
private async purgeWorkspacesAfterPurgeRetentionPeriod() {
120126
const span = opentracing.globalTracer().startSpan("purgeWorkspacesAfterPurgeRetentionPeriod");
121127
try {
122128
const now = new Date();
@@ -151,7 +157,7 @@ export class WorkspaceGarbageCollector implements Job {
151157
}
152158
}
153159

154-
protected async deleteOldPrebuilds() {
160+
private async deleteOldPrebuilds() {
155161
const span = opentracing.globalTracer().startSpan("deleteOldPrebuilds");
156162
try {
157163
const workspaces = await this.workspaceDB
@@ -160,9 +166,7 @@ export class WorkspaceGarbageCollector implements Job {
160166
this.config.workspaceGarbageCollection.minAgePrebuildDays,
161167
this.config.workspaceGarbageCollection.chunkLimit,
162168
);
163-
const deletes = await Promise.all(
164-
workspaces.map((ws) => this.deletionService.garbageCollectPrebuild({ span }, ws)),
165-
);
169+
const deletes = await Promise.all(workspaces.map((ws) => this.garbageCollectPrebuild({ span }, ws)));
166170

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

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

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

0 commit comments

Comments
 (0)