mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-27 01:19:00 +02:00
feat: track last seen clients using bulk update (#9981)
Let's not update `lastSeen` in the db on each client call
This commit is contained in:
parent
480689e828
commit
4d92d54f9a
@ -71,12 +71,18 @@ export default class ClientInstanceStore implements IClientInstanceStore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* `bulkUpsert` is beeing used instead. remove with `lastSeenBulkQuery` flag
|
||||
*/
|
||||
async setLastSeen({
|
||||
appName,
|
||||
instanceId,
|
||||
environment,
|
||||
clientIp,
|
||||
}: INewClientInstance): Promise<void> {
|
||||
const stopTimer = this.metricTimer('setLastSeen');
|
||||
|
||||
await this.db(TABLE)
|
||||
.insert({
|
||||
app_name: appName,
|
||||
@ -90,14 +96,20 @@ export default class ClientInstanceStore implements IClientInstanceStore {
|
||||
last_seen: new Date(),
|
||||
client_ip: clientIp,
|
||||
});
|
||||
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
async bulkUpsert(instances: INewClientInstance[]): Promise<void> {
|
||||
const stopTimer = this.metricTimer('bulkUpsert');
|
||||
|
||||
const rows = instances.map(mapToDb);
|
||||
await this.db(TABLE)
|
||||
.insert(rows)
|
||||
.onConflict(['app_name', 'instance_id', 'environment'])
|
||||
.merge();
|
||||
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
async delete({
|
||||
|
@ -22,6 +22,7 @@ import type { FeatureLifecycleCompletedSchema } from '../../openapi/index.js';
|
||||
import { FeatureLifecycleReadModel } from './feature-lifecycle-read-model.js';
|
||||
import type { IFeatureLifecycleReadModel } from './feature-lifecycle-read-model-type.js';
|
||||
import { STAGE_ENTERED } from '../../metric-events.js';
|
||||
import type ClientInstanceService from '../metrics/instance/instance-service.js';
|
||||
|
||||
let app: IUnleashTest;
|
||||
let db: ITestDb;
|
||||
@ -29,6 +30,7 @@ let featureLifecycleStore: IFeatureLifecycleStore;
|
||||
let eventStore: IEventStore;
|
||||
let eventBus: EventEmitter;
|
||||
let featureLifecycleReadModel: IFeatureLifecycleReadModel;
|
||||
let clientInstanceService: ClientInstanceService;
|
||||
|
||||
beforeAll(async () => {
|
||||
db = await dbInit('feature_lifecycle', getLogger, {
|
||||
@ -47,6 +49,7 @@ beforeAll(async () => {
|
||||
eventBus = app.config.eventBus;
|
||||
featureLifecycleReadModel = new FeatureLifecycleReadModel(db.rawDatabase);
|
||||
featureLifecycleStore = db.stores.featureLifecycleStore;
|
||||
clientInstanceService = app.services.clientInstanceService;
|
||||
|
||||
await app.request
|
||||
.post(`/auth/demo/login`)
|
||||
@ -62,6 +65,7 @@ afterAll(async () => {
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await clientInstanceService.bulkAdd(); // flush
|
||||
await featureLifecycleStore.deleteAll();
|
||||
});
|
||||
|
||||
|
@ -100,12 +100,22 @@ export default class ClientInstanceService {
|
||||
clientIp: string,
|
||||
): Promise<void> {
|
||||
const value = await clientMetricsSchema.validateAsync(data);
|
||||
await this.clientInstanceStore.setLastSeen({
|
||||
appName: value.appName,
|
||||
instanceId: value.instanceId,
|
||||
environment: value.environment,
|
||||
clientIp: clientIp,
|
||||
});
|
||||
|
||||
if (this.flagResolver.isEnabled('lastSeenBulkQuery')) {
|
||||
this.seenClients[this.clientKey(value)] = {
|
||||
appName: value.appName,
|
||||
instanceId: value.instanceId,
|
||||
environment: value.environment,
|
||||
clientIp: clientIp,
|
||||
};
|
||||
} else {
|
||||
await this.clientInstanceStore.setLastSeen({
|
||||
appName: value.appName,
|
||||
instanceId: value.instanceId,
|
||||
environment: value.environment,
|
||||
clientIp: clientIp,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public registerFrontendClient(data: IFrontendClientApp): void {
|
||||
|
@ -108,29 +108,6 @@ test('should accept client metrics with yes/no', () => {
|
||||
.expect(202);
|
||||
});
|
||||
|
||||
test('should accept client metrics with yes/no with metricsV2', async () => {
|
||||
const testRunner = await getSetup();
|
||||
await testRunner.request
|
||||
.post('/api/client/metrics')
|
||||
.send({
|
||||
appName: 'demo',
|
||||
instanceId: '1',
|
||||
bucket: {
|
||||
start: Date.now(),
|
||||
stop: Date.now(),
|
||||
toggles: {
|
||||
toggleA: {
|
||||
yes: 200,
|
||||
no: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.expect(202);
|
||||
|
||||
await testRunner.destroy();
|
||||
});
|
||||
|
||||
test('should accept client metrics with variants', () => {
|
||||
return request
|
||||
.post('/api/client/metrics')
|
||||
|
@ -67,6 +67,7 @@ export type IFlagKey =
|
||||
| 'featureLinks'
|
||||
| 'projectLinkTemplates'
|
||||
| 'reportUnknownFlags'
|
||||
| 'lastSeenBulkQuery'
|
||||
| 'newGettingStartedEmail';
|
||||
|
||||
export type IFlags = Partial<{ [key in IFlagKey]: boolean | Variant }>;
|
||||
@ -316,6 +317,10 @@ const flags: IFlags = {
|
||||
process.env.UNLEASH_EXPERIMENTAL_REPORT_UNKNOWN_FLAGS,
|
||||
false,
|
||||
),
|
||||
lastSeenBulkQuery: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_LAST_SEEN_BULK_QUERY,
|
||||
false,
|
||||
),
|
||||
newGettingStartedEmail: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_NEW_GETTING_STARTED_EMAIL,
|
||||
false,
|
||||
|
@ -18,6 +18,10 @@ export interface IClientInstanceStore
|
||||
Pick<INewClientInstance, 'appName' | 'instanceId'>
|
||||
> {
|
||||
bulkUpsert(instances: INewClientInstance[]): Promise<void>;
|
||||
/**
|
||||
* @deprecated
|
||||
* `bulkUpsert` is beeing used instead. remove with `lastSeenBulkQuery` flag
|
||||
*/
|
||||
setLastSeen(INewClientInstance): Promise<void>;
|
||||
insert(details: INewClientInstance): Promise<void>;
|
||||
getByAppName(appName: string): Promise<IClientInstance[]>;
|
||||
|
@ -268,6 +268,7 @@ test('should not return instances older than 24h', async () => {
|
||||
.expect(202);
|
||||
|
||||
await app.services.clientMetricsServiceV2.bulkAdd();
|
||||
await app.services.clientInstanceService.bulkAdd();
|
||||
|
||||
await db.stores.clientApplicationsStore.upsert({
|
||||
appName: metrics.appName,
|
||||
|
@ -24,6 +24,7 @@ beforeAll(async () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.services.clientInstanceService.bulkAdd(); // flush
|
||||
await Promise.all([
|
||||
db.stores.clientMetricsStoreV2.deleteAll(),
|
||||
db.stores.clientInstanceStore.deleteAll(),
|
||||
@ -73,6 +74,7 @@ test('should create instance if does not exist', async () => {
|
||||
.post('/api/client/metrics')
|
||||
.send(metricsExample)
|
||||
.expect(202);
|
||||
await app.services.clientInstanceService.bulkAdd();
|
||||
const finalInstances = await db.stores.clientInstanceStore.getAll();
|
||||
expect(finalInstances.length).toBe(1);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user