mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-19 01:17:18 +02:00
This PR does **one** thing: it changes the events for potentially stale to: - Only being emitted when potentially stale gets turned on - In doing so, it also simplifies the event that's getting emitted, removing the `data` property. - The event is also renamed to better match the existing `feature-stale-on` and `...-off` events. The addon listening was broken out into a separate PR (#4279) ## Old description This change lets all addons listen for events when features get marked or unmarked as potentially stale. ### Discussion #### All addons? Should this be available to all addons? I can't see a reason why it shouldn't be available to all addons, but I might be missing something. **Update**: spoke to a couple people. Can see no reason why this isn't okay. #### Should it be behind a flag? The feature is still behind a flag, but the event type is not. Should we gate the event being available until we actually emit the event? That would require some more code, but could yield less potential confusion. Open to hearing your thoughts.
This commit is contained in:
parent
60b9431b67
commit
4bca470543
@ -381,9 +381,9 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
||||
|
||||
async updatePotentiallyStaleFeatures(
|
||||
currentTime?: string,
|
||||
): Promise<{ name: string; potentiallyStale: boolean }[]> {
|
||||
): Promise<{ name: string; potentiallyStale: boolean; project: string }[]> {
|
||||
const query = this.db.raw(
|
||||
`SELECT name, potentially_stale, (? > (features.created_at + ((
|
||||
`SELECT name, project, potentially_stale, (? > (features.created_at + ((
|
||||
SELECT feature_types.lifetime_days
|
||||
FROM feature_types
|
||||
WHERE feature_types.id = features.type
|
||||
@ -399,9 +399,10 @@ export default class FeatureToggleStore implements IFeatureToggleStore {
|
||||
(potentially_stale ?? false) !==
|
||||
(current_staleness ?? false),
|
||||
)
|
||||
.map(({ current_staleness, name }) => ({
|
||||
.map(({ current_staleness, name, project }) => ({
|
||||
potentiallyStale: current_staleness ?? false,
|
||||
name,
|
||||
project,
|
||||
}));
|
||||
|
||||
await this.db(TABLE)
|
||||
|
@ -1,15 +1,20 @@
|
||||
import { IUnleashConfig, IUnleashStores } from '../types';
|
||||
import {
|
||||
FEATURE_POTENTIALLY_STALE_ON,
|
||||
IEvent,
|
||||
IUnleashConfig,
|
||||
IUnleashStores,
|
||||
} from '../types';
|
||||
import { createTestConfig } from '../../test/config/test-config';
|
||||
import FeatureToggleService from './feature-toggle-service';
|
||||
import { AccessService } from './access-service';
|
||||
import { IChangeRequestAccessReadModel } from 'lib/features/change-request-access-service/change-request-access-read-model';
|
||||
import { ISegmentService } from 'lib/segments/segment-service-interface';
|
||||
|
||||
test('Should store events', async () => {
|
||||
expect.assertions(4);
|
||||
test('Should only store events for potentially stale on', async () => {
|
||||
expect.assertions(2);
|
||||
const featureUpdates = [
|
||||
{ name: 'feature1', potentiallyStale: true },
|
||||
{ name: 'feature2', potentiallyStale: false },
|
||||
{ name: 'feature1', potentiallyStale: true, project: 'default' },
|
||||
{ name: 'feature2', potentiallyStale: false, project: 'default' },
|
||||
];
|
||||
|
||||
const config = createTestConfig();
|
||||
@ -18,20 +23,19 @@ test('Should store events', async () => {
|
||||
featureToggleStore: {
|
||||
updatePotentiallyStaleFeatures: () => featureUpdates,
|
||||
},
|
||||
featureTagStore: {
|
||||
getAllTagsForFeature: () => [],
|
||||
},
|
||||
eventStore: {
|
||||
batchStore: ([event1, event2]) => {
|
||||
// expect 'feature1'
|
||||
expect(event1.data).toMatchObject({
|
||||
name: 'feature1',
|
||||
potentiallyStale: true,
|
||||
batchStore: (events: IEvent[]) => {
|
||||
expect(events.length).toBe(1);
|
||||
const [event1] = events;
|
||||
|
||||
expect(event1).toMatchObject({
|
||||
featureName: 'feature1',
|
||||
project: 'default',
|
||||
type: FEATURE_POTENTIALLY_STALE_ON,
|
||||
});
|
||||
expect(event1.preData).toBeUndefined();
|
||||
// expect 'feature1'
|
||||
expect(event2.data).toMatchObject({
|
||||
name: 'feature2',
|
||||
potentiallyStale: false,
|
||||
});
|
||||
expect(event2.preData).toBeUndefined();
|
||||
},
|
||||
},
|
||||
} as unknown as IUnleashStores,
|
||||
|
@ -40,8 +40,8 @@ import {
|
||||
SKIP_CHANGE_REQUEST,
|
||||
Unsaved,
|
||||
WeightType,
|
||||
FEATURE_POTENTIALLY_STALE_UPDATED,
|
||||
StrategiesOrderChangedEvent,
|
||||
PotentiallyStaleOnEvent,
|
||||
} from '../types';
|
||||
import { Logger } from '../logger';
|
||||
import BadDataError from '../error/bad-data-error';
|
||||
@ -2077,15 +2077,19 @@ class FeatureToggleService {
|
||||
if (this.flagResolver.isEnabled('emitPotentiallyStaleEvents')) {
|
||||
if (potentiallyStaleFeatures.length > 0) {
|
||||
return this.eventStore.batchStore(
|
||||
potentiallyStaleFeatures.map(
|
||||
({ name, potentiallyStale }) => ({
|
||||
type: FEATURE_POTENTIALLY_STALE_UPDATED,
|
||||
createdBy: 'unleash-system',
|
||||
data: {
|
||||
name,
|
||||
potentiallyStale,
|
||||
},
|
||||
}),
|
||||
await Promise.all(
|
||||
potentiallyStaleFeatures
|
||||
.filter((feature) => feature.potentiallyStale)
|
||||
.map(
|
||||
async ({ name, project }) =>
|
||||
new PotentiallyStaleOnEvent({
|
||||
featureName: name,
|
||||
project,
|
||||
tags: await this.tagStore.getAllTagsForFeature(
|
||||
name,
|
||||
),
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -122,8 +122,8 @@ export const SERVICE_ACCOUNT_CREATED = 'service-account-created' as const;
|
||||
export const SERVICE_ACCOUNT_UPDATED = 'service-account-updated' as const;
|
||||
export const SERVICE_ACCOUNT_DELETED = 'service-account-deleted' as const;
|
||||
|
||||
export const FEATURE_POTENTIALLY_STALE_UPDATED =
|
||||
'feature-potentially-stale-updated' as const;
|
||||
export const FEATURE_POTENTIALLY_STALE_ON =
|
||||
'feature-potentially-stale-on' as const;
|
||||
|
||||
export const IEventTypes = [
|
||||
APPLICATION_CREATED,
|
||||
@ -227,7 +227,7 @@ export const IEventTypes = [
|
||||
SERVICE_ACCOUNT_CREATED,
|
||||
SERVICE_ACCOUNT_DELETED,
|
||||
SERVICE_ACCOUNT_UPDATED,
|
||||
FEATURE_POTENTIALLY_STALE_UPDATED,
|
||||
FEATURE_POTENTIALLY_STALE_ON,
|
||||
] as const;
|
||||
export type IEventType = typeof IEventTypes[number];
|
||||
|
||||
@ -953,3 +953,19 @@ export class ApiTokenUpdatedEvent extends BaseEvent {
|
||||
this.project = eventData.apiToken.project;
|
||||
}
|
||||
}
|
||||
|
||||
export class PotentiallyStaleOnEvent extends BaseEvent {
|
||||
readonly featureName: string;
|
||||
|
||||
readonly project: string;
|
||||
|
||||
constructor(eventData: {
|
||||
featureName: string;
|
||||
project: string;
|
||||
tags: ITag[];
|
||||
}) {
|
||||
super(FEATURE_POTENTIALLY_STALE_ON, 'unleash-system', eventData.tags);
|
||||
this.featureName = eventData.featureName;
|
||||
this.project = eventData.project;
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ export interface IFeatureToggleStore extends Store<FeatureToggle, string> {
|
||||
}): Promise<number>;
|
||||
updatePotentiallyStaleFeatures(
|
||||
currentTime?: string,
|
||||
): Promise<{ name: string; potentiallyStale: boolean }[]>;
|
||||
): Promise<{ name: string; potentiallyStale: boolean; project: string }[]>;
|
||||
isPotentiallyStale(featureName: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
|
@ -84,7 +84,7 @@ describe('potentially_stale marking', () => {
|
||||
);
|
||||
|
||||
expect(markedToggles).toStrictEqual([
|
||||
{ name: 'feature1', potentiallyStale: true },
|
||||
{ name: 'feature1', potentiallyStale: true, project: 'default' },
|
||||
]);
|
||||
});
|
||||
|
||||
@ -123,6 +123,7 @@ describe('potentially_stale marking', () => {
|
||||
expectedMarkedFeatures.map((name: string) => ({
|
||||
name,
|
||||
potentiallyStale: true,
|
||||
project: 'default',
|
||||
})),
|
||||
),
|
||||
);
|
||||
@ -173,7 +174,7 @@ describe('potentially_stale marking', () => {
|
||||
);
|
||||
|
||||
expect(markedToggles).toStrictEqual([
|
||||
{ name: 'feature1', potentiallyStale: true },
|
||||
{ name: 'feature1', potentiallyStale: true, project: 'default' },
|
||||
]);
|
||||
|
||||
expect(
|
||||
@ -207,7 +208,11 @@ describe('potentially_stale marking', () => {
|
||||
);
|
||||
|
||||
expect(markedToggles).toStrictEqual([
|
||||
{ name: 'feature1', potentiallyStale: true },
|
||||
{
|
||||
name: 'feature1',
|
||||
potentiallyStale: true,
|
||||
project: 'default',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(
|
||||
@ -221,7 +226,13 @@ describe('potentially_stale marking', () => {
|
||||
|
||||
expect(
|
||||
await featureToggleStore.updatePotentiallyStaleFeatures(),
|
||||
).toStrictEqual([{ name: 'feature1', potentiallyStale: false }]);
|
||||
).toStrictEqual([
|
||||
{
|
||||
name: 'feature1',
|
||||
potentiallyStale: false,
|
||||
project: 'default',
|
||||
},
|
||||
]);
|
||||
|
||||
const potentiallyStale =
|
||||
await featureToggleStore.isPotentiallyStale('feature1');
|
||||
|
@ -254,7 +254,7 @@ export default class FakeFeatureToggleStore implements IFeatureToggleStore {
|
||||
}
|
||||
|
||||
updatePotentiallyStaleFeatures(): Promise<
|
||||
{ name: string; potentiallyStale: boolean }[]
|
||||
{ name: string; potentiallyStale: boolean; project: string }[]
|
||||
> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user