mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01:00
chore: add edge instances to instance stats
This commit is contained in:
parent
14b4809c8e
commit
8e52e24313
@ -65,6 +65,7 @@ export const InstanceStats: FC = () => {
|
||||
},
|
||||
{ title: 'Release templates', value: stats?.releaseTemplates },
|
||||
{ title: 'Release plans', value: stats?.releasePlans },
|
||||
{ title: 'Edge instances', value: stats?.edgeInstances },
|
||||
];
|
||||
|
||||
if (stats?.versionEnterprise) {
|
||||
|
||||
@ -50,6 +50,10 @@ import {
|
||||
} from './getLicensedUsers.js';
|
||||
import { ReleasePlanStore } from '../release-plans/release-plan-store.js';
|
||||
import { ReleasePlanTemplateStore } from '../release-plans/release-plan-template-store.js';
|
||||
import {
|
||||
createFakeGetEdgeInstances,
|
||||
createGetEdgeInstances,
|
||||
} from './getEdgeInstances.js';
|
||||
|
||||
export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
||||
const { eventBus, getLogger, flagResolver } = config;
|
||||
@ -134,6 +138,7 @@ export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
||||
const getActiveUsers = createGetActiveUsers(db);
|
||||
const getProductionChanges = createGetProductionChanges(db);
|
||||
const getLicencedUsers = createGetLicensedUsers(db);
|
||||
const getEdgeInstances = createGetEdgeInstances(db);
|
||||
const versionService = new VersionService(versionServiceStores, config);
|
||||
|
||||
const instanceStatsService = new InstanceStatsService(
|
||||
@ -143,6 +148,7 @@ export const createInstanceStatsService = (db: Db, config: IUnleashConfig) => {
|
||||
getActiveUsers,
|
||||
getProductionChanges,
|
||||
getLicencedUsers,
|
||||
getEdgeInstances,
|
||||
);
|
||||
|
||||
return instanceStatsService;
|
||||
@ -199,6 +205,7 @@ export const createFakeInstanceStatsService = (config: IUnleashConfig) => {
|
||||
const getActiveUsers = createFakeGetActiveUsers();
|
||||
const getLicensedUsers = createFakeGetLicensedUsers();
|
||||
const getProductionChanges = createFakeGetProductionChanges();
|
||||
const getEdgeInstances = createFakeGetEdgeInstances();
|
||||
const versionService = new VersionService(versionServiceStores, config);
|
||||
|
||||
const instanceStatsService = new InstanceStatsService(
|
||||
@ -208,6 +215,7 @@ export const createFakeInstanceStatsService = (config: IUnleashConfig) => {
|
||||
getActiveUsers,
|
||||
getProductionChanges,
|
||||
getLicensedUsers,
|
||||
getEdgeInstances,
|
||||
);
|
||||
|
||||
return instanceStatsService;
|
||||
|
||||
59
src/lib/features/instance-stats/getEdgeInstances.ts
Normal file
59
src/lib/features/instance-stats/getEdgeInstances.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import type { Db } from '../../types/index.js';
|
||||
|
||||
const TABLE = 'edge_node_presence';
|
||||
const GRACE_PERCENTAGE = 0.05;
|
||||
|
||||
export type GetEdgeInstances = () => Promise<{
|
||||
last30: number;
|
||||
last60: number;
|
||||
last90: number;
|
||||
}>;
|
||||
|
||||
export const createGetEdgeInstances =
|
||||
(db: Db): GetEdgeInstances =>
|
||||
async () => {
|
||||
const result = await db
|
||||
.with('buckets', (qb) =>
|
||||
qb
|
||||
.from(TABLE)
|
||||
.whereRaw("bucket_ts >= NOW() - INTERVAL '90 days'")
|
||||
.groupBy('bucket_ts')
|
||||
.select(
|
||||
db.raw('bucket_ts'),
|
||||
db.raw('COUNT(*)::int AS active_nodes'),
|
||||
),
|
||||
)
|
||||
.from('buckets')
|
||||
.select({
|
||||
last30: db.raw(
|
||||
`COALESCE(CEIL(AVG(active_nodes) FILTER (WHERE bucket_ts >= NOW() - INTERVAL '30 days') * ?)::int, 0)`,
|
||||
[1 + GRACE_PERCENTAGE],
|
||||
),
|
||||
last60: db.raw(
|
||||
`COALESCE(CEIL(AVG(active_nodes) FILTER (WHERE bucket_ts >= NOW() - INTERVAL '60 days') * ?)::int, 0)`,
|
||||
[1 + GRACE_PERCENTAGE],
|
||||
),
|
||||
last90: db.raw(
|
||||
`COALESCE(CEIL(AVG(active_nodes) FILTER (WHERE bucket_ts >= NOW() - INTERVAL '90 days') * ?)::int, 0)`,
|
||||
[1 + GRACE_PERCENTAGE],
|
||||
),
|
||||
})
|
||||
.first();
|
||||
|
||||
return {
|
||||
last30: Number(result?.last30 ?? 0),
|
||||
last60: Number(result?.last60 ?? 0),
|
||||
last90: Number(result?.last90 ?? 0),
|
||||
};
|
||||
};
|
||||
|
||||
export const createFakeGetEdgeInstances =
|
||||
(
|
||||
edgeInstances: Awaited<ReturnType<GetEdgeInstances>> = {
|
||||
last30: 0,
|
||||
last60: 0,
|
||||
last90: 0,
|
||||
},
|
||||
): GetEdgeInstances =>
|
||||
() =>
|
||||
Promise.resolve(edgeInstances);
|
||||
@ -33,6 +33,7 @@ import type { GetLicensedUsers } from './getLicensedUsers.js';
|
||||
import type { IFeatureUsageInfo } from '../../services/version-service.js';
|
||||
import type { ReleasePlanTemplateStore } from '../release-plans/release-plan-template-store.js';
|
||||
import type { ReleasePlanStore } from '../release-plans/release-plan-store.js';
|
||||
import type { GetEdgeInstances } from './getEdgeInstances.js';
|
||||
|
||||
export type TimeRange = 'allTime' | '30d' | '7d';
|
||||
|
||||
@ -74,6 +75,7 @@ export interface InstanceStats {
|
||||
maxConstraintValues: number;
|
||||
releaseTemplates?: number;
|
||||
releasePlans?: number;
|
||||
edgeInstances?: Awaited<ReturnType<GetEdgeInstances>>;
|
||||
}
|
||||
|
||||
export type InstanceStatsSigned = Omit<InstanceStats, 'projects'> & {
|
||||
@ -124,6 +126,8 @@ export class InstanceStatsService {
|
||||
|
||||
getProductionChanges: GetProductionChanges;
|
||||
|
||||
getEdgeInstances: GetEdgeInstances;
|
||||
|
||||
private featureStrategiesReadModel: IFeatureStrategiesReadModel;
|
||||
|
||||
private featureStrategiesStore: IFeatureStrategiesStore;
|
||||
@ -185,6 +189,7 @@ export class InstanceStatsService {
|
||||
getActiveUsers: GetActiveUsers,
|
||||
getProductionChanges: GetProductionChanges,
|
||||
getLicencedUsers: GetLicensedUsers,
|
||||
getEdgeInstances: GetEdgeInstances,
|
||||
) {
|
||||
this.strategyStore = strategyStore;
|
||||
this.userStore = userStore;
|
||||
@ -209,6 +214,8 @@ export class InstanceStatsService {
|
||||
'getProductionChanges',
|
||||
getProductionChanges.bind(this),
|
||||
);
|
||||
this.getEdgeInstances = () =>
|
||||
this.memorize('getEdgeInstances', getEdgeInstances.bind(this));
|
||||
this.apiTokenStore = apiTokenStore;
|
||||
this.clientMetricsStore = clientMetricsStoreV2;
|
||||
this.flagResolver = flagResolver;
|
||||
@ -356,6 +363,7 @@ export class InstanceStatsService {
|
||||
maxConstraints,
|
||||
releaseTemplates,
|
||||
releasePlans,
|
||||
edgeInstances,
|
||||
] = await Promise.all([
|
||||
this.getToggleCount(),
|
||||
this.getArchivedToggleCount(),
|
||||
@ -402,6 +410,7 @@ export class InstanceStatsService {
|
||||
),
|
||||
this.getReleaseTemplates(),
|
||||
this.getReleasePlans(),
|
||||
this.getEdgeInstances(),
|
||||
]);
|
||||
|
||||
return {
|
||||
@ -442,6 +451,7 @@ export class InstanceStatsService {
|
||||
maxConstraints: maxConstraints?.count ?? 0,
|
||||
releaseTemplates,
|
||||
releasePlans,
|
||||
edgeInstances,
|
||||
};
|
||||
}
|
||||
|
||||
@ -471,6 +481,7 @@ export class InstanceStatsService {
|
||||
hostedBy,
|
||||
releaseTemplates,
|
||||
releasePlans,
|
||||
edgeInstances,
|
||||
] = await Promise.all([
|
||||
this.getToggleCount(),
|
||||
this.getRegisteredUsers(),
|
||||
@ -496,6 +507,7 @@ export class InstanceStatsService {
|
||||
this.getHostedBy(),
|
||||
this.getReleaseTemplates(),
|
||||
this.getReleasePlans(),
|
||||
this.getEdgeInstances(),
|
||||
]);
|
||||
const versionInfo = await this.versionService.getVersionInfo();
|
||||
|
||||
@ -533,6 +545,9 @@ export class InstanceStatsService {
|
||||
hostedBy,
|
||||
releaseTemplates,
|
||||
releasePlans,
|
||||
edgeInstances30: edgeInstances.last30,
|
||||
edgeInstances60: edgeInstances.last60,
|
||||
edgeInstances90: edgeInstances.last90,
|
||||
};
|
||||
return featureInfo;
|
||||
}
|
||||
|
||||
@ -284,6 +284,34 @@ export const instanceAdminStatsSchema = {
|
||||
example: 1,
|
||||
description: 'The number of release plans in this instance',
|
||||
},
|
||||
edgeInstances: {
|
||||
type: 'object',
|
||||
description:
|
||||
'The billable number of edge instances in the last 30, 60 and 90 days',
|
||||
properties: {
|
||||
last30: {
|
||||
type: 'integer',
|
||||
description:
|
||||
'The billable number of edge instances in the last 30 days',
|
||||
example: 10,
|
||||
minimum: 0,
|
||||
},
|
||||
last60: {
|
||||
type: 'integer',
|
||||
description:
|
||||
'The billable number of edge instances in the last 60 days',
|
||||
example: 12,
|
||||
minimum: 0,
|
||||
},
|
||||
last90: {
|
||||
type: 'integer',
|
||||
description:
|
||||
'The billable number of edge instances in the last 90 days',
|
||||
example: 15,
|
||||
minimum: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
sum: {
|
||||
type: 'string',
|
||||
description:
|
||||
|
||||
@ -133,6 +133,11 @@ class InstanceAdminController extends Controller {
|
||||
maxConstraintValues: 123,
|
||||
releaseTemplates: 3,
|
||||
releasePlans: 5,
|
||||
edgeInstances: {
|
||||
last30: 10,
|
||||
last60: 15,
|
||||
last90: 20,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -45,6 +45,9 @@ const fakeTelemetryData = {
|
||||
hostedBy: 'self-hosted',
|
||||
releaseTemplates: 2,
|
||||
releasePlans: 4,
|
||||
edgeInstances30: 0,
|
||||
edgeInstances60: 0,
|
||||
edgeInstances90: 0,
|
||||
};
|
||||
|
||||
test('yields current versions', async () => {
|
||||
|
||||
@ -54,6 +54,9 @@ export interface IFeatureUsageInfo {
|
||||
hostedBy: string;
|
||||
releaseTemplates: number;
|
||||
releasePlans: number;
|
||||
edgeInstances30?: number;
|
||||
edgeInstances60?: number;
|
||||
edgeInstances90?: number;
|
||||
}
|
||||
|
||||
export default class VersionService {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user