Skip to content

Commit b4a9939

Browse files
AlexTugarevroboquat
authored andcommitted
Fix issues with entitlement service
1 parent 3d71d19 commit b4a9939

10 files changed

+44
-19
lines changed

components/dashboard/src/start/CreateWorkspace.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,7 @@ function SpendingLimitReachedModal(p: { hints: any }) {
372372
const [attributedTeam, setAttributedTeam] = useState<Team | undefined>();
373373

374374
useEffect(() => {
375-
const attributionId: AttributionId | undefined =
376-
p.hints && p.hints.attributionId && AttributionId.parse(p.hints.attributionId);
375+
const attributionId: AttributionId | undefined = p.hints && p.hints.attributionId;
377376
if (attributionId) {
378377
// setAttributionId(attributionId);
379378
if (attributionId.kind === "team") {

components/server/ee/src/billing/billing-service.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { User } from "@gitpod/gitpod-protocol";
99
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
1010
import { BillableSession, BillableSessionRequest, SortOrder } from "@gitpod/gitpod-protocol/lib/usage";
1111
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
12-
import { UsageService, UsageServiceClientProvider } from "@gitpod/usage-api/lib/usage/v1/sugar";
12+
import { CachingUsageServiceClientProvider, UsageService } from "@gitpod/usage-api/lib/usage/v1/sugar";
1313
import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb";
1414
import { inject, injectable } from "inversify";
1515
import { UserService } from "../../../src/user/user-service";
@@ -24,7 +24,8 @@ export interface SpendingLimitReachedResult {
2424
export class BillingService {
2525
@inject(UserService) protected readonly userService: UserService;
2626
@inject(CostCenterDB) protected readonly costCenterDB: CostCenterDB;
27-
@inject(UsageServiceClientProvider) protected readonly usageServiceClientProvider: UsageServiceClientProvider;
27+
@inject(CachingUsageServiceClientProvider)
28+
protected readonly usageServiceClientProvider: CachingUsageServiceClientProvider;
2829

2930
async checkSpendingLimitReached(user: User): Promise<SpendingLimitReachedResult> {
3031
const attributionId = await this.userService.getWorkspaceUsageAttributionId(user);

components/server/ee/src/billing/entitlement-service-chargebee.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,13 @@ export class EntitlementServiceChargebee implements EntitlementService {
5757
hasHitParallelWorkspaceLimit(),
5858
]);
5959

60+
const result = enoughCredits && !hitParallelWorkspaceLimit;
61+
62+
console.log("mayStartWorkspace > hitParallelWorkspaceLimit " + hitParallelWorkspaceLimit);
63+
6064
return {
61-
enoughCredits: !!enoughCredits,
65+
mayStart: result,
66+
oufOfCredits: !enoughCredits,
6267
hitParallelWorkspaceLimit,
6368
};
6469
}
@@ -82,6 +87,7 @@ export class EntitlementServiceChargebee implements EntitlementService {
8287
const cachedAccountStatement = this.accountStatementProvider.getCachedStatement();
8388
const lowerBound = this.getRemainingUsageHoursLowerBound(cachedAccountStatement, date.toISOString());
8489
if (lowerBound && (lowerBound === "unlimited" || lowerBound > Accounting.MINIMUM_CREDIT_FOR_OPEN_IN_HOURS)) {
90+
console.log("checkEnoughCreditForWorkspaceStart > unlimited");
8591
return true;
8692
}
8793

@@ -90,6 +96,7 @@ export class EntitlementServiceChargebee implements EntitlementService {
9096
date.toISOString(),
9197
runningInstances,
9298
);
99+
console.log("checkEnoughCreditForWorkspaceStart > remainingUsageHours " + remainingUsageHours);
93100
return remainingUsageHours > Accounting.MINIMUM_CREDIT_FOR_OPEN_IN_HOURS;
94101
}
95102

components/server/ee/src/billing/entitlement-service-license.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export class EntitlementServiceLicense implements EntitlementService {
3030
runningInstances: Promise<WorkspaceInstance[]>,
3131
): Promise<MayStartWorkspaceResult> {
3232
// if payment is not enabled users can start as many parallel workspaces as they want
33-
return { enoughCredits: true };
33+
return { mayStart: true };
3434
}
3535

3636
async maySetTimeout(user: User, date: Date): Promise<boolean> {

components/server/ee/src/billing/entitlement-service-ubp.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ export class EntitlementServiceUBP implements EntitlementService {
5757
this.checkSpendingLimitReached(user, date),
5858
hasHitParallelWorkspaceLimit(),
5959
]);
60-
60+
const result = !spendingLimitReachedOnCostCenter && !hitParallelWorkspaceLimit;
6161
return {
62+
mayStart: result,
6263
spendingLimitReachedOnCostCenter,
6364
hitParallelWorkspaceLimit,
6465
};

components/server/ee/src/billing/entitlement-service.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,24 @@ export class EntitlementServiceImpl implements EntitlementService {
3939
): Promise<MayStartWorkspaceResult> {
4040
try {
4141
const billingMode = await this.billingModes.getBillingModeForUser(user, date);
42+
let result;
4243
switch (billingMode.mode) {
4344
case "none":
44-
return this.license.mayStartWorkspace(user, date, runningInstances);
45+
result = await this.license.mayStartWorkspace(user, date, runningInstances);
46+
break;
4547
case "chargebee":
46-
return this.chargebee.mayStartWorkspace(user, date, runningInstances);
48+
result = await this.chargebee.mayStartWorkspace(user, date, runningInstances);
49+
break;
4750
case "usage-based":
48-
return this.ubp.mayStartWorkspace(user, date, runningInstances);
51+
result = await this.ubp.mayStartWorkspace(user, date, runningInstances);
52+
break;
53+
default:
54+
throw new Error("Unsupported billing mode: " + (billingMode as any).mode); // safety net
4955
}
56+
return result;
5057
} catch (err) {
5158
log.error({ userId: user.id }, "EntitlementService error: mayStartWorkspace", err);
52-
return {};
59+
throw err;
5360
}
5461
}
5562

components/server/ee/src/user/user-service.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ import { SubscriptionService } from "@gitpod/gitpod-payment-endpoint/lib/account
2020
import { OssAllowListDB } from "@gitpod/gitpod-db/lib/oss-allowlist-db";
2121
import { HostContextProvider } from "../../../src/auth/host-context-provider";
2222
import { Config } from "../../../src/config";
23-
import { EntitlementService } from "../../../src/billing/entitlement-service";
2423

2524
export class UserServiceEE extends UserService {
2625
@inject(LicenseEvaluator) protected readonly licenseEvaluator: LicenseEvaluator;
27-
@inject(EntitlementService) protected readonly entitlementService: EntitlementService;
2826
@inject(SubscriptionService) protected readonly subscriptionService: SubscriptionService;
2927
@inject(OssAllowListDB) protected readonly OssAllowListDb: OssAllowListDB;
3028
@inject(HostContextProvider) protected readonly hostContextProvider: HostContextProvider;

components/server/ee/src/workspace/gitpod-server-impl.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,23 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
256256
): Promise<void> {
257257
await super.mayStartWorkspace(ctx, user, runningInstances);
258258

259-
const result = await this.entitlementService.mayStartWorkspace(user, new Date(), runningInstances);
260-
if (!result.enoughCredits) {
259+
let result;
260+
try {
261+
result = await this.entitlementService.mayStartWorkspace(user, new Date(), runningInstances);
262+
} catch (error) {
263+
throw new ResponseError(ErrorCodes.INTERNAL_SERVER_ERROR, `Error in Entitlement Service.`);
264+
}
265+
log.info("mayStartWorkspace", { result });
266+
if (result.mayStart) {
267+
return; // green light from entitlement service
268+
}
269+
if (!!result.oufOfCredits) {
261270
throw new ResponseError(
262271
ErrorCodes.NOT_ENOUGH_CREDIT,
263272
`Not enough monthly workspace hours. Please upgrade your account to get more hours for your workspaces.`,
264273
);
265274
}
266-
if (result.spendingLimitReachedOnCostCenter) {
275+
if (!!result.spendingLimitReachedOnCostCenter) {
267276
throw new ResponseError(
268277
ErrorCodes.PAYMENT_SPENDING_LIMIT_REACHED,
269278
"Increase spending limit and try again.",

components/server/src/billing/entitlement-service.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution";
1414
import { injectable } from "inversify";
1515

1616
export interface MayStartWorkspaceResult {
17+
mayStart: boolean;
18+
1719
hitParallelWorkspaceLimit?: HitParallelWorkspaceLimit;
18-
enoughCredits?: boolean;
20+
21+
oufOfCredits?: boolean;
1922

2023
/** Usage-Based Pricing: AttributionId of the CostCenter that reached it's spending limit */
2124
spendingLimitReachedOnCostCenter?: AttributionId;
@@ -72,7 +75,7 @@ export class CommunityEntitlementService implements EntitlementService {
7275
date: Date,
7376
runningInstances: Promise<WorkspaceInstance[]>,
7477
): Promise<MayStartWorkspaceResult> {
75-
return { enoughCredits: true };
78+
return { mayStart: true };
7679
}
7780

7881
async maySetTimeout(user: User, date: Date): Promise<boolean> {

components/server/src/workspace/gitpod-server-impl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
10471047
// make sure we've checked that the user has enough credit before consuming any resources.
10481048
// Be sure to check this before prebuilds and create workspace, too!
10491049
let context = await contextPromise;
1050-
await Promise.all([this.mayStartWorkspace(ctx, user, runningInstancesPromise)]);
1050+
await this.mayStartWorkspace(ctx, user, runningInstancesPromise);
10511051

10521052
if (SnapshotContext.is(context)) {
10531053
// TODO(janx): Remove snapshot access tracking once we're certain that enforcing repository read access doesn't disrupt the snapshot UX.

0 commit comments

Comments
 (0)