Skip to content

Commit 1763878

Browse files
abelanger5grutt
andauthored
feat: managed compute and benchmarks (#1419)
* wip global can state * wip managed compute state * wip * service name * names * names * fix * can build * fix reason * rm IAC * fix token * build * trigger code * snipits * build * v1 -> v0 * benchmarking guide and limit fix * rm dupe --------- Co-authored-by: gabriel ruttner <[email protected]>
1 parent 9a5b21b commit 1763878

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+4071
-320
lines changed

frontend/app/src/lib/api/generated/cloud/Api.ts

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable */
22
/* tslint:disable */
3+
// @ts-nocheck
34
/*
45
* ---------------------------------------------------------------
56
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
@@ -14,6 +15,7 @@ import {
1415
APIError,
1516
APIErrors,
1617
Build,
18+
CreateManagedWorkerFromTemplateRequest,
1719
CreateManagedWorkerRequest,
1820
CreateOrUpdateAutoscalingRequest,
1921
FeatureFlags,
@@ -27,10 +29,10 @@ import {
2729
ManagedWorkerEventList,
2830
ManagedWorkerList,
2931
Matrix,
32+
MonthlyComputeCost,
3033
RuntimeConfigActionsResponse,
3134
TenantBillingState,
3235
TenantSubscription,
33-
TenantUsage,
3436
UpdateManagedWorkerRequest,
3537
UpdateTenantSubscription,
3638
VectorPushRequest,
@@ -206,6 +208,46 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
206208
format: "json",
207209
...params,
208210
});
211+
/**
212+
* @description Create a managed worker from a template
213+
*
214+
* @tags Managed Worker
215+
* @name ManagedWorkerTemplateCreate
216+
* @summary Create Managed Worker from Template
217+
* @request POST:/api/v1/cloud/tenants/{tenant}/managed-worker/template
218+
* @secure
219+
*/
220+
managedWorkerTemplateCreate = (
221+
tenant: string,
222+
data: CreateManagedWorkerFromTemplateRequest,
223+
params: RequestParams = {},
224+
) =>
225+
this.request<ManagedWorker, APIErrors>({
226+
path: `/api/v1/cloud/tenants/${tenant}/managed-worker/template`,
227+
method: "POST",
228+
body: data,
229+
secure: true,
230+
type: ContentType.Json,
231+
format: "json",
232+
...params,
233+
});
234+
/**
235+
* @description Get the total compute costs for the tenant
236+
*
237+
* @tags Cost
238+
* @name ComputeCostGet
239+
* @summary Get Managed Worker Cost
240+
* @request GET:/api/v1/cloud/tenants/{tenant}/managed-worker/cost
241+
* @secure
242+
*/
243+
computeCostGet = (tenant: string, params: RequestParams = {}) =>
244+
this.request<MonthlyComputeCost, APIErrors>({
245+
path: `/api/v1/cloud/tenants/${tenant}/managed-worker/cost`,
246+
method: "GET",
247+
secure: true,
248+
format: "json",
249+
...params,
250+
});
209251
/**
210252
* @description Get a managed worker for the tenant
211253
*
@@ -596,23 +638,6 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
596638
format: "json",
597639
...params,
598640
});
599-
/**
600-
* @description Get usage for a tenant
601-
*
602-
* @tags Billing
603-
* @name UsageGet
604-
* @summary Get usage for a tenant
605-
* @request GET:/api/v1/usage/tenants/{tenant}
606-
* @secure
607-
*/
608-
usageGet = (tenant: string, params: RequestParams = {}) =>
609-
this.request<TenantUsage, any>({
610-
path: `/api/v1/usage/tenants/${tenant}`,
611-
method: "GET",
612-
secure: true,
613-
format: "json",
614-
...params,
615-
});
616641
/**
617642
* @description Push a log entry for the tenant
618643
*

frontend/app/src/lib/api/generated/cloud/data-contracts.ts

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable */
22
/* tslint:disable */
3+
// @ts-nocheck
34
/*
45
* ---------------------------------------------------------------
56
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
@@ -25,6 +26,11 @@ export interface APICloudMetadata {
2526
* @example true
2627
*/
2728
metricsEnabled?: boolean;
29+
/**
30+
* whether the tenant requires billing for managed compute
31+
* @example true
32+
*/
33+
requireBillingForManagedCompute?: boolean;
2834
}
2935

3036
export interface APIErrors {
@@ -129,7 +135,7 @@ export type ListGithubBranchesResponse = GithubBranch[];
129135
export interface ManagedWorker {
130136
metadata: APIResourceMeta;
131137
name: string;
132-
buildConfig: ManagedWorkerBuildConfig;
138+
buildConfig?: ManagedWorkerBuildConfig;
133139
isIac: boolean;
134140
/** A map of environment variables to set for the worker */
135141
envVars: Record<string, string>;
@@ -165,7 +171,7 @@ export interface BuildStep {
165171
export interface ManagedWorkerRuntimeConfig {
166172
metadata: APIResourceMeta;
167173
numReplicas: number;
168-
autoscaling?: CreateOrUpdateAutoscalingRequest;
174+
autoscaling?: AutoscalingConfig;
169175
/** The kind of CPU to use for the worker */
170176
cpuKind: string;
171177
/** The number of CPUs to use for the worker */
@@ -382,11 +388,6 @@ export enum TenantSubscriptionStatus {
382388
Canceled = "canceled",
383389
}
384390

385-
export interface TenantUsage {
386-
/** The usage of the tenant. */
387-
usage: string;
388-
}
389-
390391
export interface Coupon {
391392
/** The name of the coupon. */
392393
name: string;
@@ -543,13 +544,30 @@ export interface WorkflowRunEventsMetricsCounts {
543544
results?: WorkflowRunEventsMetric[];
544545
}
545546

547+
export interface AutoscalingConfig {
548+
waitDuration: string;
549+
rollingWindowDuration: string;
550+
utilizationScaleUpThreshold: number;
551+
utilizationScaleDownThreshold: number;
552+
increment: number;
553+
targetKind: AutoscalingTargetKind;
554+
minAwakeReplicas: number;
555+
maxReplicas: number;
556+
scaleToZero: boolean;
557+
}
558+
559+
export enum AutoscalingTargetKind {
560+
PORTER = "PORTER",
561+
FLY = "FLY",
562+
}
563+
546564
export interface CreateOrUpdateAutoscalingRequest {
547565
waitDuration: string;
548566
rollingWindowDuration: string;
549567
utilizationScaleUpThreshold: number;
550568
utilizationScaleDownThreshold: number;
551569
increment: number;
552-
targetKind?: "PORTER" | "FLY";
570+
targetKind?: AutoscalingTargetKind;
553571
minAwakeReplicas: number;
554572
maxReplicas: number;
555573
scaleToZero: boolean;
@@ -569,3 +587,19 @@ export interface CreateFlyAutoscalingRequest {
569587
autoscalingKey: string;
570588
currentReplicas: number;
571589
}
590+
591+
export enum TemplateOptions {
592+
QUICKSTART_PYTHON = "QUICKSTART_PYTHON",
593+
QUICKSTART_TYPESCRIPT = "QUICKSTART_TYPESCRIPT",
594+
QUICKSTART_GO = "QUICKSTART_GO",
595+
}
596+
597+
export interface CreateManagedWorkerFromTemplateRequest {
598+
name: TemplateOptions;
599+
}
600+
601+
export interface MonthlyComputeCost {
602+
cost: number;
603+
hasCreditsRemaining: boolean;
604+
creditsRemaining?: number;
605+
}

frontend/app/src/lib/api/generated/cloud/http-client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable */
22
/* tslint:disable */
3+
// @ts-nocheck
34
/*
45
* ---------------------------------------------------------------
56
* ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##

frontend/app/src/lib/api/queries.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createQueryKeyStore } from '@lukemorales/query-key-factory';
33
import api, { cloudApi } from './api';
44
import invariant from 'tiny-invariant';
55
import { WebhookWorkerCreateRequest } from '.';
6+
import { TemplateOptions } from './generated/cloud/data-contracts';
67

78
type ListEventQuery = Parameters<typeof api.eventList>[1];
89
type ListRateLimitsQuery = Parameters<typeof api.rateLimitList>[1];
@@ -29,6 +30,21 @@ export const queries = createQueryKeyStore({
2930
queryKey: ['billing-state:get', tenant],
3031
queryFn: async () => (await cloudApi.tenantBillingStateGet(tenant)).data,
3132
}),
33+
34+
getComputeCost: (tenant: string) => ({
35+
queryKey: ['compute-cost:get', tenant],
36+
queryFn: async () => (await cloudApi.computeCostGet(tenant)).data,
37+
}),
38+
createComputeDemoTemplate: (tenant: string, template: TemplateOptions) => ({
39+
queryKey: ['compute-demo-template:create', tenant, template],
40+
queryFn: async () =>
41+
(
42+
await cloudApi.managedWorkerTemplateCreate(tenant, {
43+
name: template,
44+
})
45+
).data,
46+
}),
47+
3248
getManagedWorker: (worker: string) => ({
3349
queryKey: ['managed-worker:get', worker],
3450
queryFn: async () => (await cloudApi.managedWorkerGet(worker)).data,

frontend/app/src/lib/atoms.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { Tenant, TenantVersion, queries } from './api';
33
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
44
import { useCallback, useEffect, useMemo, useState } from 'react';
55
import { useQuery } from '@tanstack/react-query';
6+
import useCloudApiMeta from '@/pages/auth/hooks/use-cloud-api-meta';
7+
import { TenantBillingState } from './api/generated/cloud/data-contracts';
8+
import { Evaluate } from './can/shared/permission.base';
69

710
const getInitialValue = <T>(key: string, defaultValue?: T): T | undefined => {
811
const item = localStorage.getItem(key);
@@ -30,16 +33,31 @@ export const lastTenantAtom = atom(
3033
},
3134
);
3235

36+
type Plan = 'free' | 'starter' | 'growth';
37+
38+
export type BillingContext = {
39+
state: TenantBillingState | undefined;
40+
setPollBilling: (pollBilling: boolean) => void;
41+
plan: Plan;
42+
hasPaymentMethods: boolean;
43+
};
44+
45+
type Can = (evalFn: Evaluate) => ReturnType<Evaluate>;
46+
3347
type TenantContextPresent = {
3448
tenant: Tenant;
3549
tenantId: string;
3650
setTenant: (tenant: Tenant) => void;
51+
billing: BillingContext;
52+
can: Can;
3753
};
3854

3955
type TenantContextMissing = {
4056
tenant: undefined;
4157
tenantId: undefined;
4258
setTenant: (tenant: Tenant) => void;
59+
billing: undefined;
60+
can: Can;
4361
};
4462

4563
type TenantContext = TenantContextPresent | TenantContextMissing;
@@ -63,6 +81,7 @@ export function useTenant(): TenantContext {
6381
const membershipsQuery = useQuery({
6482
...queries.user.listTenantMemberships,
6583
});
84+
6685
const memberships = useMemo(
6786
() => membershipsQuery.data?.rows || [],
6887
[membershipsQuery.data],
@@ -164,20 +183,68 @@ export function useTenant(): TenantContext {
164183
search: params.toString(),
165184
});
166185
}
167-
}, [lastRedirected, navigate, params, pathname, tenant]);
186+
}, [lastRedirected, navigate, params, pathname, previewV0, tenant]);
187+
188+
// Tenant Billing State
189+
190+
const [pollBilling, setPollBilling] = useState(false);
191+
192+
const cloudMeta = useCloudApiMeta();
193+
194+
const billingState = useQuery({
195+
...queries.cloud.billing(tenant!.metadata.id),
196+
enabled: tenant && !!cloudMeta?.data.canBill,
197+
refetchInterval: pollBilling ? 1000 : false,
198+
});
199+
200+
const subscriptionPlan: Plan = useMemo(() => {
201+
const plan = billingState.data?.subscription?.plan;
202+
if (!plan) {
203+
return 'free';
204+
}
205+
return plan as Plan;
206+
}, [billingState.data?.subscription?.plan]);
207+
208+
const hasPaymentMethods = useMemo(() => {
209+
return (billingState.data?.paymentMethods?.length || 0) > 0;
210+
}, [billingState.data?.paymentMethods]);
211+
212+
const billingContext: BillingContext = useMemo(() => {
213+
return {
214+
state: billingState.data,
215+
setPollBilling,
216+
plan: subscriptionPlan,
217+
hasPaymentMethods,
218+
};
219+
}, [billingState.data, setPollBilling, subscriptionPlan, hasPaymentMethods]);
220+
221+
const can = useCallback(
222+
(evalFn: Evaluate) => {
223+
return evalFn({
224+
tenant,
225+
billing: billingContext,
226+
meta: cloudMeta?.data,
227+
});
228+
},
229+
[billingContext, cloudMeta?.data, tenant],
230+
);
168231

169232
if (!tenant) {
170233
return {
171234
tenant: undefined,
172235
tenantId: undefined,
173236
setTenant,
237+
billing: undefined,
238+
can,
174239
};
175240
}
176241

177242
return {
178243
tenant,
179244
tenantId: tenant.metadata.id,
180245
setTenant,
246+
billing: billingContext,
247+
can,
181248
};
182249
}
183250

0 commit comments

Comments
 (0)