Skip to content

Commit

Permalink
[server] Fix usage of AccountStatementProvider by making it cache per…
Browse files Browse the repository at this point in the history
… userId
  • Loading branch information
geropl authored and roboquat committed Aug 29, 2022
1 parent 7f537e2 commit a2b7412
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export class GarbageCollectedCache<T> {
if (!entry) {
return undefined;
}
// Still valid?
if (entry.expiryDate < Date.now()) {
this.store.delete(entry.key);
return undefined;
}
return entry.value;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class EntitlementServiceChargebee implements EntitlementService {
runningInstances: Promise<WorkspaceInstance[]>,
): Promise<boolean> {
// As retrieving a full AccountStatement is expensive we want to cache it as much as possible.
const cachedAccountStatement = this.accountStatementProvider.getCachedStatement();
const cachedAccountStatement = this.accountStatementProvider.getCachedStatement(userId);
const lowerBound = this.getRemainingUsageHoursLowerBound(cachedAccountStatement, date.toISOString());
if (lowerBound && (lowerBound === "unlimited" || lowerBound > Accounting.MINIMUM_CREDIT_FOR_OPEN_IN_HOURS)) {
return true;
Expand Down Expand Up @@ -108,7 +108,7 @@ export class EntitlementServiceChargebee implements EntitlementService {
return "unlimited";
}

const diffInMillis = new Date(cachedStatement.endDate).getTime() - new Date(date).getTime();
const diffInMillis = Math.max(0, new Date(cachedStatement.endDate).getTime() - new Date(date).getTime());
const maxPossibleUsage = millisecondsToHours(diffInMillis) * MAX_PARALLEL_WORKSPACES;
return cachedStatement.remainingHours - maxPossibleUsage;
}
Expand Down
1 change: 0 additions & 1 deletion components/server/ee/src/billing/entitlement-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export class EntitlementServiceImpl implements EntitlementService {
const verification = await this.verificationService.needsVerification(user);
if (verification) {
return {
mayStart: false,
needsVerification: true,
};
}
Expand Down
2 changes: 1 addition & 1 deletion components/server/ee/src/container-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ export const productionEEContainerModule = new ContainerModule((bind, unbind, is
// GitpodServerImpl (stateful per user)
rebind(GitpodServerImpl).to(GitpodServerEEImpl).inRequestScope();
bind(EligibilityService).toSelf().inRequestScope();
bind(AccountStatementProvider).toSelf().inRequestScope();

// various
rebind(HostContainerMapping).to(HostContainerMappingEE).inSingletonScope();
bind(EMailDomainService).to(EMailDomainServiceImpl).inSingletonScope();
rebind(BlockedUserFilter).toService(EMailDomainService);
bind(SnapshotService).toSelf().inSingletonScope();
bind(AccountStatementProvider).toSelf().inSingletonScope();

bind(UserDeletionServiceEE).toSelf().inSingletonScope();
rebind(UserDeletionService).to(UserDeletionServiceEE).inSingletonScope();
Expand Down
17 changes: 8 additions & 9 deletions components/server/ee/src/user/account-statement-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { injectable, inject } from "inversify";
import { WorkspaceInstance } from "@gitpod/gitpod-protocol";
import { AccountStatement } from "@gitpod/gitpod-protocol/lib/accounting-protocol";
import { AccountService } from "@gitpod/gitpod-payment-endpoint/lib/accounting";
import { GarbageCollectedCache } from "@gitpod/gitpod-protocol/lib/util/garbage-collected-cache";

export type CachedAccountStatement = Pick<AccountStatement, "remainingHours" | "endDate">;

Expand All @@ -19,20 +20,18 @@ export type CachedAccountStatement = Pick<AccountStatement, "remainingHours" | "
export class AccountStatementProvider {
@inject(AccountService) protected readonly accountService: AccountService;

protected cachedStatement: CachedAccountStatement | undefined;
/**
* AccountStatements, cached by userId
*/
protected readonly cachedStatements = new GarbageCollectedCache<CachedAccountStatement>(5 * 60, 10 * 60);

setCachedStatement(cachedStatement: CachedAccountStatement) {
this.cachedStatement = cachedStatement;
}

getCachedStatement(): CachedAccountStatement | undefined {
return this.cachedStatement;
getCachedStatement(userId: string): CachedAccountStatement | undefined {
return this.cachedStatements.get(userId);
}

async getAccountStatement(userId: string, date: string): Promise<AccountStatement> {
const statement = await this.accountService.getAccountStatement(userId, date);
// Fill cache
this.setCachedStatement({
this.cachedStatements.set(userId, {
remainingHours: statement.remainingHours,
endDate: statement.endDate,
});
Expand Down

0 comments on commit a2b7412

Please sign in to comment.