1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-31 01:16:01 +02:00

fix: publish events about unannounced applications

fixes: #747
This commit is contained in:
Christopher Kolstad 2021-03-05 14:01:15 +01:00 committed by GitHub
parent f4aba80763
commit 9e649118e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 154 additions and 5 deletions

View File

@ -5,6 +5,7 @@ const NotFoundError = require('../error/notfound-error');
const COLUMNS = [
'app_name',
'created_at',
'created_by',
'updated_at',
'description',
'strategies',
@ -20,6 +21,7 @@ const mapRow = row => ({
updatedAt: row.updated_at,
description: row.description,
strategies: row.strategies,
createdBy: row.created_by,
url: row.url,
color: row.color,
icon: row.icon,
@ -29,6 +31,8 @@ const remapRow = (input, old = {}) => ({
app_name: input.appName,
updated_at: input.updatedAt,
description: input.description || old.description,
created_by: input.createdBy || old.createdBy,
announced: input.announced || old.announced || false,
url: input.url || old.url,
color: input.color || old.color,
icon: input.icon || old.icon,
@ -118,6 +122,26 @@ class ClientApplicationsDb {
? this.getAppsForStrategy(filter.strategyName)
: this.getAll();
}
async getUnannounced() {
const rows = await this.db(TABLE)
.select(COLUMNS)
.where('announced', false);
return rows.map(mapRow);
}
/** *
* Updates all rows that have announced = false to announced =true and returns the rows altered
* @return {[app]} - Apps that hadn't been announced
*/
async setUnannouncedToAnnounced() {
const rows = await this.db(TABLE)
.update({ announced: true })
.where('announced', false)
.whereNotNull('announced')
.returning(COLUMNS);
return rows.map(mapRow);
}
}
module.exports = ClientApplicationsDb;

View File

@ -10,6 +10,7 @@ const { clientRegisterSchema } = require('./register-schema');
const { APPLICATION_CREATED } = require('../../event-type');
const FIVE_SECONDS = 5 * 1000;
const FIVE_MINUTES = 5 * 60 * 1000;
module.exports = class ClientMetricsService {
constructor(
@ -21,7 +22,11 @@ module.exports = class ClientMetricsService {
clientInstanceStore,
eventStore,
},
{ getLogger, bulkInterval = FIVE_SECONDS },
{
getLogger,
bulkInterval = FIVE_SECONDS,
announcementInterval: appAnnouncementInterval = FIVE_MINUTES,
},
) {
this.globalCount = 0;
this.apps = {};
@ -63,6 +68,7 @@ module.exports = class ClientMetricsService {
});
this.seenClients = {};
setInterval(() => this.bulkAdd(), bulkInterval);
setInterval(() => this.announceUnannounced(), appAnnouncementInterval);
clientMetricsStore.on('metrics', m => this.addPayload(m));
}
@ -78,10 +84,26 @@ module.exports = class ClientMetricsService {
});
}
async announceUnannounced() {
if (this.clientAppStore) {
const appsToAnnounce = await this.clientAppStore.setUnannouncedToAnnounced();
if (appsToAnnounce.length > 0) {
const events = appsToAnnounce.map(app => {
return {
type: APPLICATION_CREATED,
createdBy: app.createdBy,
data: app,
};
});
await this.eventStore.batchStore(events);
}
}
}
async registerClient(data, clientIp) {
const value = await clientRegisterSchema.validateAsync(data);
value.clientIp = clientIp;
this.logger.info(`${JSON.stringify(data)}`);
value.createdBy = clientIp;
this.seenClients[this.clientKey(value)] = value;
}

View File

@ -0,0 +1,24 @@
'use strict';
exports.up = function(db, cb) {
db.runSql(
`
ALTER TABLE client_applications ADD COLUMN announced boolean DEFAULT false;
UPDATE client_applications SET announced = true;
`,
cb,
);
};
exports.down = function(db, cb) {
db.runSql(
`
ALTER TABLE client_applications DROP COLUMN announced;
`,
cb,
);
};
exports._meta = {
version: 1,
};

View File

@ -0,0 +1,18 @@
'use strict';
exports.up = function(db, cb) {
db.runSql(
`
ALTER TABLE client_applications ADD COLUMN created_by TEXT;
`,
cb,
);
};
exports.down = function(db, cb) {
db.runSql('ALTER TABLE client_applications DROP COLUMN created_by;', cb);
};
exports._meta = {
version: 1,
};

View File

@ -24,17 +24,20 @@
"applications": [
{
"appName": "demo-app-1",
"strategies": ["default"]
"strategies": ["default"],
"announced": true
},
{
"appName": "demo-app-2",
"strategies": ["default", "extra"],
"description": "hello"
"description": "hello",
"announced": true
},
{
"appName": "deletable-app",
"strategies": ["default"],
"description": "Some desc"
"description": "Some desc",
"announced": true
}
],
"clientInstances": [

View File

@ -0,0 +1,58 @@
const test = require('ava');
const faker = require('faker');
const dbInit = require('../helpers/database-init');
const getLogger = require('../../fixtures/no-logger');
const ClientMetricsService = require('../../../lib/services/client-metrics');
const { APPLICATION_CREATED } = require('../../../lib/event-type');
let stores;
let clientMetricsService;
test.before(async () => {
const db = await dbInit('client_metrics_service_serial', getLogger);
stores = db.stores;
clientMetricsService = new ClientMetricsService(stores, {
getLogger,
bulkInterval: 500,
announcementInterval: 2000,
});
});
test.after(async () => {
await stores.db.destroy();
});
test.serial('Apps registered should be announced', async t => {
t.plan(3);
const clientRegistration = {
appName: faker.internet.domainName(),
instanceId: faker.random.uuid(),
strategies: ['default'],
started: Date.now(),
interval: faker.random.number(),
icon: '',
description: faker.company.catchPhrase(),
color: faker.internet.color(),
};
const differentClient = {
appName: faker.lorem.slug(2),
instanceId: faker.random.uuid(),
strategies: ['default'],
started: Date.now(),
interval: faker.random.number(),
icon: '',
description: faker.company.catchPhrase(),
color: faker.internet.color(),
};
await clientMetricsService.registerClient(clientRegistration, '127.0.0.1');
await clientMetricsService.registerClient(differentClient, '127.0.0.1');
await new Promise(res => setTimeout(res, 1200));
const first = await stores.clientApplicationsStore.getUnannounced();
t.is(first.length, 2);
await clientMetricsService.registerClient(clientRegistration, '127.0.0.1');
await new Promise(res => setTimeout(res, 2000));
const second = await stores.clientApplicationsStore.getUnannounced();
t.is(second.length, 0);
const events = await stores.eventStore.getEvents();
const appCreatedEvents = events.filter(e => e.type === APPLICATION_CREATED);
t.is(appCreatedEvents.length, 2);
});