7
7
import { CostCenterDB } from "@gitpod/gitpod-db/lib" ;
8
8
import { User } from "@gitpod/gitpod-protocol" ;
9
9
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution" ;
10
- import { BillableSession , BillableSessionRequest , SortOrder } from "@gitpod/gitpod-protocol/lib/usage " ;
10
+ import { ConfigCatClientFactory } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server " ;
11
11
import { log } from "@gitpod/gitpod-protocol/lib/util/logging" ;
12
- import { CachingUsageServiceClientProvider , UsageService } from "@gitpod/usage-api/lib/usage/v1/sugar" ;
13
- import { Timestamp } from "google-protobuf/google/protobuf/timestamp_pb" ;
12
+ import { GetUpcomingInvoiceResponse } from "@gitpod/usage-api/lib/usage/v1/billing_pb" ;
13
+ import {
14
+ CachingUsageServiceClientProvider ,
15
+ CachingBillingServiceClientProvider ,
16
+ } from "@gitpod/usage-api/lib/usage/v1/sugar" ;
14
17
import { inject , injectable } from "inversify" ;
15
18
import { UserService } from "../../../src/user/user-service" ;
16
19
@@ -26,6 +29,9 @@ export class BillingService {
26
29
@inject ( CostCenterDB ) protected readonly costCenterDB : CostCenterDB ;
27
30
@inject ( CachingUsageServiceClientProvider )
28
31
protected readonly usageServiceClientProvider : CachingUsageServiceClientProvider ;
32
+ @inject ( CachingBillingServiceClientProvider )
33
+ protected readonly billingServiceClientProvider : CachingBillingServiceClientProvider ;
34
+ @inject ( ConfigCatClientFactory ) protected readonly configCatClientFactory : ConfigCatClientFactory ;
29
35
30
36
async checkSpendingLimitReached ( user : User ) : Promise < SpendingLimitReachedResult > {
31
37
const attributionId = await this . userService . getWorkspaceUsageAttributionId ( user ) ;
@@ -40,50 +46,53 @@ export class BillingService {
40
46
} ;
41
47
}
42
48
43
- const allSessions = await this . listBilledUsage ( {
44
- attributionId : AttributionId . render ( attributionId ) ,
45
- startedTimeOrder : SortOrder . Descending ,
46
- } ) ;
47
- const totalUsage = allSessions . map ( ( s ) => s . credits ) . reduce ( ( a , b ) => a + b , 0 ) ;
48
- if ( totalUsage >= costCenter . spendingLimit ) {
49
+ if ( ! ( await this . isSpendingLimitCheckEnabled ( user ) ) ) {
50
+ return {
51
+ reached : false ,
52
+ attributionId,
53
+ } ;
54
+ }
55
+
56
+ const upcomingInvoice = await this . getUpcomingInvoice ( attributionId ) ;
57
+ const currentUsage = upcomingInvoice . getCredits ( ) ;
58
+ if ( currentUsage >= costCenter . spendingLimit ) {
59
+ log . info ( { userId : user . id } , "Spending limit reached" , {
60
+ attributionId,
61
+ currentUsage,
62
+ spendingLimit : costCenter . spendingLimit ,
63
+ } ) ;
49
64
return {
50
65
reached : true ,
51
66
attributionId,
52
67
} ;
53
- } else if ( totalUsage > costCenter . spendingLimit * 0.8 ) {
68
+ } else if ( currentUsage > costCenter . spendingLimit * 0.8 ) {
69
+ log . info ( { userId : user . id } , "Spending limit almost reached" , {
70
+ attributionId,
71
+ currentUsage,
72
+ spendingLimit : costCenter . spendingLimit ,
73
+ } ) ;
54
74
return {
55
75
reached : false ,
56
76
almostReached : true ,
57
77
attributionId,
58
78
} ;
59
79
}
80
+
60
81
return {
61
82
reached : false ,
62
83
attributionId,
63
84
} ;
64
85
}
65
86
66
- // TODO (gpl): Replace this with call to stripeService.getInvoice()
67
- async listBilledUsage ( req : BillableSessionRequest ) : Promise < BillableSession [ ] > {
68
- const { attributionId, startedTimeOrder, from, to } = req ;
69
- let timestampFrom ;
70
- let timestampTo ;
87
+ protected async isSpendingLimitCheckEnabled ( user : User ) : Promise < boolean > {
88
+ // introducing this enablement flag to be able to explicitly control the spending limit check during rollout
89
+ return await this . configCatClientFactory ( ) . getValueAsync ( "isSpendingLimitCheckEnabled" , false , {
90
+ user : user ,
91
+ } ) ;
92
+ }
71
93
72
- if ( from ) {
73
- timestampFrom = Timestamp . fromDate ( new Date ( from ) ) ;
74
- }
75
- if ( to ) {
76
- timestampTo = Timestamp . fromDate ( new Date ( to ) ) ;
77
- }
78
- const usageClient = this . usageServiceClientProvider . getDefault ( ) ;
79
- const response = await usageClient . listBilledUsage (
80
- { } ,
81
- attributionId ,
82
- startedTimeOrder as number ,
83
- timestampFrom ,
84
- timestampTo ,
85
- ) ;
86
- const sessions = response . getSessionsList ( ) . map ( ( s ) => UsageService . mapBilledSession ( s ) ) ;
87
- return sessions ;
94
+ async getUpcomingInvoice ( attributionId : AttributionId ) : Promise < GetUpcomingInvoiceResponse > {
95
+ const response = await this . billingServiceClientProvider . getDefault ( ) . getUpcomingInvoice ( attributionId ) ;
96
+ return response ;
88
97
}
89
98
}
0 commit comments