mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
feat: segment delta (#8990)
Now the delta endpoint also always returns all the segments.
This commit is contained in:
parent
37b55eff5a
commit
138ba35d7a
@ -1,8 +1,10 @@
|
||||
import type {
|
||||
IClientSegment,
|
||||
IEventStore,
|
||||
IFeatureToggleDeltaQuery,
|
||||
IFeatureToggleQuery,
|
||||
IFlagResolver,
|
||||
ISegmentReadModel,
|
||||
} from '../../../types';
|
||||
import type ConfigurationRevisionService from '../../feature-toggle/configuration-revision-service';
|
||||
import { UPDATE_REVISION } from '../../feature-toggle/configuration-revision-service';
|
||||
@ -21,6 +23,7 @@ export type RevisionDeltaEntry = {
|
||||
updated: FeatureConfigurationDeltaClient[];
|
||||
revisionId: number;
|
||||
removed: DeletedFeature[];
|
||||
segments: IClientSegment[];
|
||||
};
|
||||
|
||||
export type Revision = {
|
||||
@ -96,6 +99,8 @@ export class ClientFeatureToggleDelta {
|
||||
|
||||
private delta: Revisions = {};
|
||||
|
||||
private segments: IClientSegment[];
|
||||
|
||||
private eventStore: IEventStore;
|
||||
|
||||
private currentRevisionId: number = 0;
|
||||
@ -106,8 +111,11 @@ export class ClientFeatureToggleDelta {
|
||||
|
||||
private configurationRevisionService: ConfigurationRevisionService;
|
||||
|
||||
private readonly segmentReadModel: ISegmentReadModel;
|
||||
|
||||
constructor(
|
||||
clientFeatureToggleDeltaReadModel: IClientFeatureToggleDeltaReadModel,
|
||||
segmentReadModel: ISegmentReadModel,
|
||||
eventStore: IEventStore,
|
||||
configurationRevisionService: ConfigurationRevisionService,
|
||||
flagResolver: IFlagResolver,
|
||||
@ -117,10 +125,12 @@ export class ClientFeatureToggleDelta {
|
||||
this.clientFeatureToggleDeltaReadModel =
|
||||
clientFeatureToggleDeltaReadModel;
|
||||
this.flagResolver = flagResolver;
|
||||
this.segmentReadModel = segmentReadModel;
|
||||
this.onUpdateRevisionEvent = this.onUpdateRevisionEvent.bind(this);
|
||||
this.delta = {};
|
||||
|
||||
this.initRevisionId();
|
||||
this.updateSegments();
|
||||
this.configurationRevisionService.on(
|
||||
UPDATE_REVISION,
|
||||
this.onUpdateRevisionEvent,
|
||||
@ -146,6 +156,10 @@ export class ClientFeatureToggleDelta {
|
||||
if (!hasDelta) {
|
||||
await this.initEnvironmentDelta(environment);
|
||||
}
|
||||
const hasSegments = this.segments;
|
||||
if (!hasSegments) {
|
||||
await this.updateSegments();
|
||||
}
|
||||
|
||||
// Should get the latest state if revision does not exist or if sdkRevision is not present
|
||||
// We should be able to do this without going to the database by merging revisions from the delta with
|
||||
@ -162,6 +176,7 @@ export class ClientFeatureToggleDelta {
|
||||
revisionId: this.currentRevisionId,
|
||||
// @ts-ignore
|
||||
updated: await this.getClientFeatures({ environment }),
|
||||
segments: this.segments,
|
||||
removed: [],
|
||||
};
|
||||
}
|
||||
@ -178,12 +193,18 @@ export class ClientFeatureToggleDelta {
|
||||
projects,
|
||||
);
|
||||
|
||||
return Promise.resolve(compressedRevision);
|
||||
const revisionResponse = {
|
||||
...compressedRevision,
|
||||
segments: this.segments,
|
||||
};
|
||||
|
||||
return Promise.resolve(revisionResponse);
|
||||
}
|
||||
|
||||
private async onUpdateRevisionEvent() {
|
||||
if (this.flagResolver.isEnabled('deltaApi')) {
|
||||
await this.listenToRevisionChange();
|
||||
await this.updateSegments();
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,4 +290,8 @@ export class ClientFeatureToggleDelta {
|
||||
await this.clientFeatureToggleDeltaReadModel.getAll(query);
|
||||
return result;
|
||||
}
|
||||
|
||||
private async updateSegments(): Promise<void> {
|
||||
this.segments = await this.segmentReadModel.getActiveForClient();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import ConfigurationRevisionService from '../../feature-toggle/configuration-rev
|
||||
import type { IUnleashConfig } from '../../../types';
|
||||
import type { Db } from '../../../db/db';
|
||||
import ClientFeatureToggleDeltaReadModel from './client-feature-toggle-delta-read-model';
|
||||
import { SegmentReadModel } from '../../segment/segment-read-model';
|
||||
|
||||
export const createClientFeatureToggleDelta = (
|
||||
db: Db,
|
||||
@ -19,8 +20,11 @@ export const createClientFeatureToggleDelta = (
|
||||
const configurationRevisionService =
|
||||
ConfigurationRevisionService.getInstance({ eventStore }, config);
|
||||
|
||||
const segmentReadModel = new SegmentReadModel(db);
|
||||
|
||||
const clientFeatureToggleDelta = new ClientFeatureToggleDelta(
|
||||
clientFeatureToggleDeltaReadModel,
|
||||
segmentReadModel,
|
||||
eventStore,
|
||||
configurationRevisionService,
|
||||
flagResolver,
|
||||
|
@ -12,7 +12,17 @@ exports[`should match snapshot from /api/client/features 1`] = `
|
||||
"stale": false,
|
||||
"strategies": [
|
||||
{
|
||||
"constraints": [],
|
||||
"constraints": [
|
||||
{
|
||||
"caseInsensitive": false,
|
||||
"contextName": "appName",
|
||||
"inverted": false,
|
||||
"operator": "IN",
|
||||
"values": [
|
||||
"test",
|
||||
],
|
||||
},
|
||||
],
|
||||
"name": "flexibleRollout",
|
||||
"parameters": {
|
||||
"groupId": "test1",
|
||||
|
@ -30,7 +30,15 @@ const getApiClientResponse = (project = 'default') => [
|
||||
strategies: [
|
||||
{
|
||||
name: 'flexibleRollout',
|
||||
constraints: [],
|
||||
constraints: [
|
||||
{
|
||||
contextName: 'appName',
|
||||
operator: 'IN',
|
||||
values: ['test'],
|
||||
caseInsensitive: false,
|
||||
inverted: false,
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
rollout: '100',
|
||||
stickiness: 'default',
|
||||
@ -82,6 +90,7 @@ const cleanup = async (db: ITestDb, app: IUnleashTest) => {
|
||||
),
|
||||
),
|
||||
);
|
||||
await db.stores.segmentStore.deleteAll();
|
||||
};
|
||||
|
||||
const setupFeatures = async (
|
||||
@ -94,10 +103,24 @@ const setupFeatures = async (
|
||||
await app.createFeature('test1', project);
|
||||
await app.createFeature('test2', project);
|
||||
|
||||
const { body: segmentBody } = await app.createSegment({
|
||||
name: 'a',
|
||||
constraints: [
|
||||
{
|
||||
contextName: 'appName',
|
||||
operator: 'IN',
|
||||
values: ['test'],
|
||||
caseInsensitive: false,
|
||||
inverted: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await app.addStrategyToFeatureEnv(
|
||||
{
|
||||
name: 'flexibleRollout',
|
||||
constraints: [],
|
||||
segments: [segmentBody.id],
|
||||
parameters: {
|
||||
rollout: '100',
|
||||
stickiness: 'default',
|
||||
@ -323,19 +346,3 @@ test('should match snapshot from /api/client/features', async () => {
|
||||
|
||||
expect(result.body).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match with /api/client/delta', async () => {
|
||||
await setupFeatures(db, app);
|
||||
|
||||
const { body } = await app.request
|
||||
.get('/api/client/features')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200);
|
||||
|
||||
const { body: deltaBody } = await app.request
|
||||
.get('/api/client/delta')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200);
|
||||
|
||||
expect(body.features).toMatchObject(deltaBody.updated);
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type EventEmitter from 'events';
|
||||
import { CLIENT_METRICS } from './internals';
|
||||
|
||||
const REQUEST_TIME = 'request_time';
|
||||
const DB_TIME = 'db_time';
|
||||
|
@ -34,6 +34,14 @@ export const clientFeaturesDeltaSchema = {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
segments: {
|
||||
description:
|
||||
'A list of [Segments](https://docs.getunleash.io/reference/segments) configured for this Unleash instance',
|
||||
type: 'array',
|
||||
items: {
|
||||
$ref: '#/components/schemas/clientSegmentSchema',
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
schemas: {
|
||||
|
Loading…
Reference in New Issue
Block a user