1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-18 13:48:58 +02:00

change update to upsert

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
andreas-unleash 2023-09-25 19:48:56 +03:00
parent 6de0414732
commit f64ba6b60c
No known key found for this signature in database
GPG Key ID: DB82A1577B38F66B
3 changed files with 72 additions and 16 deletions

View File

@ -171,24 +171,37 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
return present; return present;
} }
private upsert = (params: any) => {
const { table, object, constraint } = params;
const insert = this.db(table).insert(object);
const update = this.db.queryBuilder().update(object);
return this.db
.raw(`? ON CONFLICT ${constraint} DO ? returning *`, [
insert,
update,
])
.get('rows')
.get(0);
};
async setLastSeen(data: LastSeenInput[]): Promise<void> { async setLastSeen(data: LastSeenInput[]): Promise<void> {
const now = new Date(); const now = new Date();
const environmentArrays = this.mapMetricDataToEnvBuckets(data); const enhancedData = data.map((value) => ({
try { feature_name: value.featureName,
for (const env of Object.keys(environmentArrays)) { last_seen_at: now,
const toggleNames = environmentArrays[env].sort(); environment: value.environment,
await this.db(FEATURE_ENVIRONMENTS_METRICS_TABLE) }));
.upsert({ last_seen_at: now }) const dataToPersist: typeof enhancedData = [];
.where('environment', env) for (const input of enhancedData) {
.whereIn( if (await this.exists(input.feature_name)) {
'feature_name', dataToPersist.push(input);
this.db(FEATURE_ENVIRONMENTS_METRICS_TABLE)
.select('feature_name')
.whereIn('feature_name', toggleNames)
.forUpdate()
.skipLocked(),
);
} }
}
try {
await this.db(FEATURE_ENVIRONMENTS_METRICS_TABLE)
.insert(dataToPersist)
.onConflict(['feature_name', 'environment'])
.merge(['last_seen_at']);
} catch (err) { } catch (err) {
this.logger.error('Could not update lastSeen, error: ', err); this.logger.error('Could not update lastSeen, error: ', err);
} }

View File

@ -58,7 +58,7 @@ export class LastSeenService {
.filter( .filter(
(clientMetric) => clientMetric.yes > 0 || clientMetric.no > 0, (clientMetric) => clientMetric.yes > 0 || clientMetric.no > 0,
) )
.forEach((clientMetric) => { .forEach(async (clientMetric) => {
const key = `${clientMetric.featureName}:${clientMetric.environment}`; const key = `${clientMetric.featureName}:${clientMetric.environment}`;
this.lastSeenToggles.set(key, { this.lastSeenToggles.set(key, {
featureName: clientMetric.featureName, featureName: clientMetric.featureName,

View File

@ -129,3 +129,46 @@ test('Should not update anything for 0 toggles', async () => {
service.destroy(); service.destroy();
}); });
test('Should handle 1000 toggle updates', async () => {
// jest.useFakeTimers();
const service = new LastSeenService(stores, config, 30);
const time = Date.now();
for (let i = 0; i <= 1000; i++) {
await stores.featureToggleStore.create('default', { name: `tb${i}` });
}
const metrics: IClientMetricsEnv[] = [];
for (let i = 0; i < 999; i++) {
metrics.push({
featureName: `tb${i}`,
appName: 'some-App',
environment: 'default',
timestamp: new Date(time),
yes: 1,
no: 0,
});
}
metrics.push({
featureName: 'tb1000',
appName: 'some-App',
environment: 'default',
timestamp: new Date(time),
yes: 0,
no: 0,
});
service.updateLastSeen(metrics);
// bypass interval waiting
await service.store();
const t1 = await stores.featureToggleStore.get('tb1');
const t2 = await stores.featureToggleStore.get('tb1000');
expect(t2.lastSeenAt).toBeNull();
expect(t1.lastSeenAt.getTime()).toBeGreaterThanOrEqual(time);
service.destroy();
});