1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-10-18 20:09:08 +02:00
unleash.unleash/src/lib/db/client-instance-store.ts

178 lines
4.7 KiB
TypeScript
Raw Normal View History

import EventEmitter from 'events';
import { Knex } from 'knex';
import { Logger, LogProvider } from '../logger';
import Timeout = NodeJS.Timeout;
import {
IClientInstance,
IClientInstanceStore,
INewClientInstance,
} from '../types/stores/client-instance-store';
2016-11-04 09:03:13 +01:00
2021-05-02 21:11:17 +02:00
const metricsHelper = require('../util/metrics-helper');
2021-04-29 10:21:29 +02:00
const { DB_TIME } = require('../metric-events');
2017-06-28 10:17:14 +02:00
const COLUMNS = [
'app_name',
'instance_id',
'sdk_version',
2017-06-28 10:17:14 +02:00
'client_ip',
'last_seen',
'created_at',
];
2016-11-04 09:03:13 +01:00
const TABLE = 'client_instances';
const ONE_DAY = 24 * 61 * 60 * 1000;
const mapRow = (row) => ({
appName: row.app_name,
instanceId: row.instance_id,
sdkVersion: row.sdk_version,
clientIp: row.client_ip,
lastSeen: row.last_seen,
createdAt: row.created_at,
});
const mapToDb = (client) => ({
app_name: client.appName,
instance_id: client.instanceId,
sdk_version: client.sdkVersion || '',
client_ip: client.clientIp,
last_seen: client.lastSeen || 'now()',
});
export default class ClientInstanceStore implements IClientInstanceStore {
private db: Knex;
private logger: Logger;
private eventBus: EventEmitter;
private metricTimer: Function;
private timer: Timeout;
constructor(db: Knex, eventBus: EventEmitter, getLogger: LogProvider) {
this.db = db;
this.eventBus = eventBus;
this.logger = getLogger('client-instance-store.ts');
this.metricTimer = (action) =>
2020-09-18 09:05:09 +02:00
metricsHelper.wrapTimer(eventBus, DB_TIME, {
store: 'instance',
action,
});
const clearer = () => this._removeInstancesOlderThanTwoDays();
setTimeout(clearer, 10).unref();
this.timer = setInterval(clearer, ONE_DAY).unref();
}
async _removeInstancesOlderThanTwoDays(): Promise<void> {
2020-09-18 09:05:09 +02:00
const rows = await this.db(TABLE)
2017-06-28 10:17:14 +02:00
.whereRaw("created_at < now() - interval '2 days'")
2020-09-18 09:05:09 +02:00
.del();
if (rows > 0) {
this.logger.debug(`Deleted ${rows} instances`);
}
}
async bulkUpsert(instances: INewClientInstance[]): Promise<void> {
const rows = instances.map(mapToDb);
await this.db(TABLE)
.insert(rows)
.onConflict(['app_name', 'instance_id'])
.merge();
2016-11-04 09:03:13 +01:00
}
async delete({
appName,
instanceId,
}: Pick<INewClientInstance, 'appName' | 'instanceId'>): Promise<void> {
await this.db(TABLE)
.where({ app_name: appName, instance_id: instanceId })
.del();
}
async deleteAll(): Promise<void> {
await this.db(TABLE).del();
}
async get({
appName,
instanceId,
}: Pick<
INewClientInstance,
'appName' | 'instanceId'
>): Promise<IClientInstance> {
const row = await this.db(TABLE)
.where({ app_name: appName, instance_id: instanceId })
.first();
return mapRow(row);
}
async exists({
appName,
instanceId,
}: Pick<INewClientInstance, 'appName' | 'instanceId'>): Promise<boolean> {
const result = await this.db.raw(
`SELECT EXISTS (SELECT 1 FROM ${TABLE} WHERE app_name = ? AND instance_id = ?) AS present`,
[appName, instanceId],
);
const { present } = result.rows[0];
return present;
2016-11-04 09:03:13 +01:00
}
async insert(details: INewClientInstance): Promise<void> {
2020-12-16 14:56:48 +01:00
const stopTimer = this.metricTimer('insert');
2020-09-18 09:05:09 +02:00
await this.db(TABLE)
.insert(mapToDb(details))
.onConflict(['app_name', 'instance_id'])
.merge();
2020-09-18 09:05:09 +02:00
stopTimer();
2016-11-04 09:03:13 +01:00
}
async getAll(): Promise<IClientInstance[]> {
2020-12-16 14:56:48 +01:00
const stopTimer = this.metricTimer('getAll');
2020-09-18 09:05:09 +02:00
const rows = await this.db
2016-11-04 09:03:13 +01:00
.select(COLUMNS)
.from(TABLE)
2020-09-18 09:05:09 +02:00
.orderBy('last_seen', 'desc');
const toggles = rows.map(mapRow);
stopTimer();
return toggles;
2016-11-04 09:03:13 +01:00
}
async getByAppName(appName: string): Promise<IClientInstance[]> {
2020-09-18 09:05:09 +02:00
const rows = await this.db
.select()
.from(TABLE)
.where('app_name', appName)
2020-09-18 09:05:09 +02:00
.orderBy('last_seen', 'desc');
return rows.map(mapRow);
}
async getDistinctApplications(): Promise<string[]> {
2020-09-18 09:05:09 +02:00
const rows = await this.db
.distinct('app_name')
.select(['app_name'])
.from(TABLE)
2020-09-18 09:05:09 +02:00
.orderBy('app_name', 'desc');
return rows.map((r) => r.app_name);
}
2020-09-25 09:39:12 +02:00
async deleteForApplication(appName: string): Promise<void> {
return this.db(TABLE).where('app_name', appName).del();
2020-09-25 09:39:12 +02:00
}
destroy(): void {
clearInterval(this.timer);
}
2017-06-28 10:17:14 +02:00
}