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

feat:metrics for outgoing integrations (#7921)

This commit is contained in:
David Leek 2024-08-20 09:00:28 +02:00 committed by GitHub
parent 58f2b5ab1c
commit e714a7fe2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 144 additions and 13 deletions

View File

@ -4,6 +4,7 @@ import noLogger from '../../test/fixtures/no-logger';
import SlackAddon from './slack'; import SlackAddon from './slack';
import type { IAddonConfig, IFlagResolver } from '../types'; import type { IAddonConfig, IFlagResolver } from '../types';
import type { IntegrationEventsService } from '../services'; import type { IntegrationEventsService } from '../services';
import type EventEmitter from 'events';
beforeEach(() => { beforeEach(() => {
nock.disableNetConnect(); nock.disableNetConnect();
@ -16,6 +17,7 @@ const ARGS: IAddonConfig = {
unleashUrl: url, unleashUrl: url,
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: {} as IFlagResolver,
eventBus: {} as EventEmitter,
}; };
test('Does not retry if request succeeds', async () => { test('Does not retry if request succeeds', async () => {

View File

@ -5,6 +5,7 @@ import type { IAddonConfig, IAddonDefinition } from '../types/model';
import type { IEvent } from '../types/events'; import type { IEvent } from '../types/events';
import type { IntegrationEventsService } from '../features/integration-events/integration-events-service'; import type { IntegrationEventsService } from '../features/integration-events/integration-events-service';
import type { IntegrationEventWriteModel } from '../features/integration-events/integration-events-store'; import type { IntegrationEventWriteModel } from '../features/integration-events/integration-events-store';
import type EventEmitter from 'events';
import type { IFlagResolver } from '../types'; import type { IFlagResolver } from '../types';
export default abstract class Addon { export default abstract class Addon {
@ -16,11 +17,18 @@ export default abstract class Addon {
integrationEventsService: IntegrationEventsService; integrationEventsService: IntegrationEventsService;
eventBus: EventEmitter;
flagResolver: IFlagResolver; flagResolver: IFlagResolver;
constructor( constructor(
definition: IAddonDefinition, definition: IAddonDefinition,
{ getLogger, integrationEventsService, flagResolver }: IAddonConfig, {
getLogger,
integrationEventsService,
flagResolver,
eventBus,
}: IAddonConfig,
) { ) {
this.logger = getLogger(`addon/${definition.name}`); this.logger = getLogger(`addon/${definition.name}`);
const { error } = addonDefinitionSchema.validate(definition); const { error } = addonDefinitionSchema.validate(definition);
@ -34,6 +42,7 @@ export default abstract class Addon {
this._name = definition.name; this._name = definition.name;
this._definition = definition; this._definition = definition;
this.integrationEventsService = integrationEventsService; this.integrationEventsService = integrationEventsService;
this.eventBus = eventBus;
this.flagResolver = flagResolver; this.flagResolver = flagResolver;
} }

View File

@ -10,6 +10,7 @@ import DatadogAddon from './datadog';
import noLogger from '../../test/fixtures/no-logger'; import noLogger from '../../test/fixtures/no-logger';
import { import {
type IFlagKey,
serializeDates, serializeDates,
type IAddonConfig, type IAddonConfig,
type IFlagResolver, type IFlagResolver,
@ -24,7 +25,8 @@ const ARGS: IAddonConfig = {
getLogger: noLogger, getLogger: noLogger,
unleashUrl: 'http://some-url.com', unleashUrl: 'http://some-url.com',
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
eventBus: {} as any,
}; };
jest.mock( jest.mock(

View File

@ -2,7 +2,11 @@ import Addon from './addon';
import definition from './datadog-definition'; import definition from './datadog-definition';
import Mustache from 'mustache'; import Mustache from 'mustache';
import { type IAddonConfig, serializeDates } from '../types'; import {
type IAddonConfig,
type IFlagResolver,
serializeDates,
} from '../types';
import { import {
type FeatureEventFormatter, type FeatureEventFormatter,
FeatureEventFormatterMd, FeatureEventFormatterMd,
@ -10,6 +14,7 @@ import {
} from './feature-event-formatter-md'; } from './feature-event-formatter-md';
import type { IEvent } from '../types/events'; import type { IEvent } from '../types/events';
import type { IntegrationEventState } from '../features/integration-events/integration-events-store'; import type { IntegrationEventState } from '../features/integration-events/integration-events-store';
import { ADDON_EVENTS_HANDLED } from '../metric-events';
interface IDatadogParameters { interface IDatadogParameters {
url: string; url: string;
@ -29,12 +34,15 @@ interface DDRequestBody {
export default class DatadogAddon extends Addon { export default class DatadogAddon extends Addon {
private msgFormatter: FeatureEventFormatter; private msgFormatter: FeatureEventFormatter;
flagResolver: IFlagResolver;
constructor(config: IAddonConfig) { constructor(config: IAddonConfig) {
super(definition, config); super(definition, config);
this.msgFormatter = new FeatureEventFormatterMd( this.msgFormatter = new FeatureEventFormatterMd(
config.unleashUrl, config.unleashUrl,
LinkStyle.MD, LinkStyle.MD,
); );
this.flagResolver = config.flagResolver;
} }
async handleEvent( async handleEvent(
@ -107,6 +115,13 @@ export default class DatadogAddon extends Addon {
state = 'failed'; state = 'failed';
const failedMessage = `Datadog Events API request failed with status code: ${res.status}.`; const failedMessage = `Datadog Events API request failed with status code: ${res.status}.`;
stateDetails.push(failedMessage); stateDetails.push(failedMessage);
if (this.flagResolver.isEnabled('addonUsageMetrics')) {
this.eventBus.emit(ADDON_EVENTS_HANDLED, {
result: state,
destination: 'datadog',
});
}
this.logger.warn(failedMessage); this.logger.warn(failedMessage);
} }

View File

@ -6,6 +6,7 @@ import {
type IAddonConfig, type IAddonConfig,
type IEvent, type IEvent,
serializeDates, serializeDates,
type IFlagKey,
} from '../types'; } from '../types';
import type { Logger } from '../logger'; import type { Logger } from '../logger';
@ -26,7 +27,8 @@ const ARGS: IAddonConfig = {
getLogger: noLogger, getLogger: noLogger,
unleashUrl: 'http://some-url.com', unleashUrl: 'http://some-url.com',
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
eventBus: {} as any,
}; };
jest.mock( jest.mock(

View File

@ -6,6 +6,7 @@ import {
type IAddonConfig, type IAddonConfig,
type IEvent, type IEvent,
type IEventType, type IEventType,
type IFlagResolver,
serializeDates, serializeDates,
} from '../types'; } from '../types';
import { import {
@ -16,6 +17,7 @@ import {
import { gzip } from 'node:zlib'; import { gzip } from 'node:zlib';
import { promisify } from 'util'; import { promisify } from 'util';
import type { IntegrationEventState } from '../features/integration-events/integration-events-store'; import type { IntegrationEventState } from '../features/integration-events/integration-events-store';
import { ADDON_EVENTS_HANDLED } from '../metric-events';
const asyncGzip = promisify(gzip); const asyncGzip = promisify(gzip);
@ -39,12 +41,15 @@ interface INewRelicRequestBody {
export default class NewRelicAddon extends Addon { export default class NewRelicAddon extends Addon {
private msgFormatter: FeatureEventFormatter; private msgFormatter: FeatureEventFormatter;
flagResolver: IFlagResolver;
constructor(config: IAddonConfig) { constructor(config: IAddonConfig) {
super(definition, config); super(definition, config);
this.msgFormatter = new FeatureEventFormatterMd( this.msgFormatter = new FeatureEventFormatterMd(
config.unleashUrl, config.unleashUrl,
LinkStyle.MD, LinkStyle.MD,
); );
this.flagResolver = config.flagResolver;
} }
async handleEvent( async handleEvent(
@ -117,6 +122,13 @@ export default class NewRelicAddon extends Addon {
this.logger.warn(failedMessage); this.logger.warn(failedMessage);
} }
if (this.flagResolver.isEnabled('addonUsageMetrics')) {
this.eventBus.emit(ADDON_EVENTS_HANDLED, {
result: state,
destination: 'new-relic',
});
}
this.registerEvent({ this.registerEvent({
integrationId, integrationId,
state, state,

View File

@ -3,6 +3,7 @@ import SlackAppAddon from './slack-app';
import { type ChatPostMessageArguments, ErrorCode } from '@slack/web-api'; import { type ChatPostMessageArguments, ErrorCode } from '@slack/web-api';
import { import {
type IAddonConfig, type IAddonConfig,
type IFlagKey,
type IFlagResolver, type IFlagResolver,
serializeDates, serializeDates,
SYSTEM_USER_ID, SYSTEM_USER_ID,
@ -28,7 +29,8 @@ const ARGS: IAddonConfig = {
getLogger, getLogger,
unleashUrl: 'http://some-url.com', unleashUrl: 'http://some-url.com',
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
eventBus: {} as any,
}; };
let postMessage = jest.fn().mockImplementation((options) => { let postMessage = jest.fn().mockImplementation((options) => {

View File

@ -13,7 +13,11 @@ import {
import Addon from './addon'; import Addon from './addon';
import slackAppDefinition from './slack-app-definition'; import slackAppDefinition from './slack-app-definition';
import { type IAddonConfig, serializeDates } from '../types'; import {
type IAddonConfig,
type IFlagResolver,
serializeDates,
} from '../types';
import { import {
type FeatureEventFormatter, type FeatureEventFormatter,
FeatureEventFormatterMd, FeatureEventFormatterMd,
@ -21,6 +25,7 @@ import {
} from './feature-event-formatter-md'; } from './feature-event-formatter-md';
import type { IEvent } from '../types/events'; import type { IEvent } from '../types/events';
import type { IntegrationEventState } from '../features/integration-events/integration-events-store'; import type { IntegrationEventState } from '../features/integration-events/integration-events-store';
import { ADDON_EVENTS_HANDLED } from '../metric-events';
interface ISlackAppAddonParameters { interface ISlackAppAddonParameters {
accessToken: string; accessToken: string;
@ -30,6 +35,8 @@ interface ISlackAppAddonParameters {
export default class SlackAppAddon extends Addon { export default class SlackAppAddon extends Addon {
private msgFormatter: FeatureEventFormatter; private msgFormatter: FeatureEventFormatter;
flagResolver: IFlagResolver;
private accessToken?: string; private accessToken?: string;
private slackClient?: WebClient; private slackClient?: WebClient;
@ -40,6 +47,7 @@ export default class SlackAppAddon extends Addon {
args.unleashUrl, args.unleashUrl,
LinkStyle.SLACK, LinkStyle.SLACK,
); );
this.flagResolver = args.flagResolver;
} }
async handleEvent( async handleEvent(
@ -168,6 +176,13 @@ export default class SlackAppAddon extends Addon {
stateDetails.push(eventErrorMessage); stateDetails.push(eventErrorMessage);
this.logger.warn(eventErrorMessage); this.logger.warn(eventErrorMessage);
const errorMessage = this.parseError(error); const errorMessage = this.parseError(error);
if (this.flagResolver.isEnabled('addonUsageMetrics')) {
this.eventBus.emit(ADDON_EVENTS_HANDLED, {
result: state,
destination: 'slack-app',
});
}
stateDetails.push(errorMessage); stateDetails.push(errorMessage);
this.logger.warn(errorMessage, error); this.logger.warn(errorMessage, error);
} finally { } finally {

View File

@ -11,6 +11,7 @@ import SlackAddon from './slack';
import noLogger from '../../test/fixtures/no-logger'; import noLogger from '../../test/fixtures/no-logger';
import { import {
type IAddonConfig, type IAddonConfig,
type IFlagKey,
type IFlagResolver, type IFlagResolver,
serializeDates, serializeDates,
SYSTEM_USER_ID, SYSTEM_USER_ID,
@ -25,7 +26,8 @@ const ARGS: IAddonConfig = {
getLogger: noLogger, getLogger: noLogger,
unleashUrl: 'http://some-url.com', unleashUrl: 'http://some-url.com',
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
eventBus: {} as any,
}; };
jest.mock( jest.mock(

View File

@ -1,7 +1,11 @@
import Addon from './addon'; import Addon from './addon';
import slackDefinition from './slack-definition'; import slackDefinition from './slack-definition';
import { type IAddonConfig, serializeDates } from '../types'; import {
type IAddonConfig,
type IFlagResolver,
serializeDates,
} from '../types';
import { import {
type FeatureEventFormatter, type FeatureEventFormatter,
@ -10,6 +14,7 @@ import {
} from './feature-event-formatter-md'; } from './feature-event-formatter-md';
import type { IEvent } from '../types/events'; import type { IEvent } from '../types/events';
import type { IntegrationEventState } from '../features/integration-events/integration-events-store'; import type { IntegrationEventState } from '../features/integration-events/integration-events-store';
import { ADDON_EVENTS_HANDLED } from '../metric-events';
interface ISlackAddonParameters { interface ISlackAddonParameters {
url: string; url: string;
@ -21,12 +26,15 @@ interface ISlackAddonParameters {
export default class SlackAddon extends Addon { export default class SlackAddon extends Addon {
private msgFormatter: FeatureEventFormatter; private msgFormatter: FeatureEventFormatter;
flagResolver: IFlagResolver;
constructor(args: IAddonConfig) { constructor(args: IAddonConfig) {
super(slackDefinition, args); super(slackDefinition, args);
this.msgFormatter = new FeatureEventFormatterMd( this.msgFormatter = new FeatureEventFormatterMd(
args.unleashUrl, args.unleashUrl,
LinkStyle.SLACK, LinkStyle.SLACK,
); );
this.flagResolver = args.flagResolver;
} }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
@ -121,6 +129,13 @@ export default class SlackAddon extends Addon {
state = 'successWithErrors'; state = 'successWithErrors';
const successWithErrorsMessage = `Some (${failedRequests.length} of ${results.length}) Slack webhook requests failed. Status codes: ${codes}.`; const successWithErrorsMessage = `Some (${failedRequests.length} of ${results.length}) Slack webhook requests failed. Status codes: ${codes}.`;
stateDetails.push(successWithErrorsMessage); stateDetails.push(successWithErrorsMessage);
if (this.flagResolver.isEnabled('addonUsageMetrics')) {
this.eventBus.emit(ADDON_EVENTS_HANDLED, {
result: state,
destination: 'slack',
});
}
this.logger.warn(successWithErrorsMessage); this.logger.warn(successWithErrorsMessage);
} }

View File

@ -12,6 +12,7 @@ import TeamsAddon from './teams';
import noLogger from '../../test/fixtures/no-logger'; import noLogger from '../../test/fixtures/no-logger';
import { import {
type IAddonConfig, type IAddonConfig,
type IFlagKey,
type IFlagResolver, type IFlagResolver,
serializeDates, serializeDates,
SYSTEM_USER_ID, SYSTEM_USER_ID,
@ -26,7 +27,8 @@ const ARGS: IAddonConfig = {
getLogger: noLogger, getLogger: noLogger,
unleashUrl: 'http://some-url.com', unleashUrl: 'http://some-url.com',
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
eventBus: {} as any,
}; };
jest.mock( jest.mock(

View File

@ -1,13 +1,18 @@
import Addon from './addon'; import Addon from './addon';
import teamsDefinition from './teams-definition'; import teamsDefinition from './teams-definition';
import { type IAddonConfig, serializeDates } from '../types'; import {
type IAddonConfig,
type IFlagResolver,
serializeDates,
} from '../types';
import { import {
type FeatureEventFormatter, type FeatureEventFormatter,
FeatureEventFormatterMd, FeatureEventFormatterMd,
} from './feature-event-formatter-md'; } from './feature-event-formatter-md';
import type { IEvent } from '../types/events'; import type { IEvent } from '../types/events';
import type { IntegrationEventState } from '../features/integration-events/integration-events-store'; import type { IntegrationEventState } from '../features/integration-events/integration-events-store';
import { ADDON_EVENTS_HANDLED } from '../metric-events';
interface ITeamsParameters { interface ITeamsParameters {
url: string; url: string;
@ -16,9 +21,12 @@ interface ITeamsParameters {
export default class TeamsAddon extends Addon { export default class TeamsAddon extends Addon {
private msgFormatter: FeatureEventFormatter; private msgFormatter: FeatureEventFormatter;
flagResolver: IFlagResolver;
constructor(args: IAddonConfig) { constructor(args: IAddonConfig) {
super(teamsDefinition, args); super(teamsDefinition, args);
this.msgFormatter = new FeatureEventFormatterMd(args.unleashUrl); this.msgFormatter = new FeatureEventFormatterMd(args.unleashUrl);
this.flagResolver = args.flagResolver;
} }
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
@ -97,6 +105,13 @@ export default class TeamsAddon extends Addon {
state = 'failed'; state = 'failed';
const failedMessage = `Teams webhook request failed with status code: ${res.status}.`; const failedMessage = `Teams webhook request failed with status code: ${res.status}.`;
stateDetails.push(failedMessage); stateDetails.push(failedMessage);
if (this.flagResolver.isEnabled('addonUsageMetrics')) {
this.eventBus.emit(ADDON_EVENTS_HANDLED, {
result: state,
destination: 'teams',
});
}
this.logger.warn(failedMessage); this.logger.warn(failedMessage);
} }

View File

@ -7,6 +7,7 @@ import WebhookAddon from './webhook';
import noLogger from '../../test/fixtures/no-logger'; import noLogger from '../../test/fixtures/no-logger';
import { import {
type IAddonConfig, type IAddonConfig,
type IFlagKey,
type IFlagResolver, type IFlagResolver,
serializeDates, serializeDates,
SYSTEM_USER_ID, SYSTEM_USER_ID,
@ -21,7 +22,8 @@ const ARGS: IAddonConfig = {
getLogger: noLogger, getLogger: noLogger,
unleashUrl: 'http://some-url.com', unleashUrl: 'http://some-url.com',
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
eventBus: {} as any,
}; };
jest.mock( jest.mock(

View File

@ -2,16 +2,22 @@ import Mustache from 'mustache';
import Addon from './addon'; import Addon from './addon';
import definition from './webhook-definition'; import definition from './webhook-definition';
import type { IEvent } from '../types/events'; import type { IEvent } from '../types/events';
import { type IAddonConfig, serializeDates } from '../types'; import {
type IAddonConfig,
type IFlagResolver,
serializeDates,
} from '../types';
import type { IntegrationEventState } from '../features/integration-events/integration-events-store'; import type { IntegrationEventState } from '../features/integration-events/integration-events-store';
import { import {
type FeatureEventFormatter, type FeatureEventFormatter,
FeatureEventFormatterMd, FeatureEventFormatterMd,
LinkStyle, LinkStyle,
} from './feature-event-formatter-md'; } from './feature-event-formatter-md';
import { ADDON_EVENTS_HANDLED } from '../metric-events';
interface IParameters { interface IParameters {
url: string; url: string;
serviceName?: string;
bodyTemplate?: string; bodyTemplate?: string;
contentType?: string; contentType?: string;
authorization?: string; authorization?: string;
@ -21,12 +27,15 @@ interface IParameters {
export default class Webhook extends Addon { export default class Webhook extends Addon {
private msgFormatter: FeatureEventFormatter; private msgFormatter: FeatureEventFormatter;
flagResolver: IFlagResolver;
constructor(args: IAddonConfig) { constructor(args: IAddonConfig) {
super(definition, args); super(definition, args);
this.msgFormatter = new FeatureEventFormatterMd( this.msgFormatter = new FeatureEventFormatterMd(
args.unleashUrl, args.unleashUrl,
LinkStyle.MD, LinkStyle.MD,
); );
this.flagResolver = args.flagResolver;
} }
async handleEvent( async handleEvent(
@ -94,6 +103,13 @@ export default class Webhook extends Addon {
state = 'failed'; state = 'failed';
const failedMessage = `Webhook request failed with status code: ${res.status}.`; const failedMessage = `Webhook request failed with status code: ${res.status}.`;
stateDetails.push(failedMessage); stateDetails.push(failedMessage);
if (this.flagResolver.isEnabled('addonUsageMetrics')) {
this.eventBus.emit(ADDON_EVENTS_HANDLED, {
result: state,
destination: 'webhook',
});
}
this.logger.warn(failedMessage); this.logger.warn(failedMessage);
} }

View File

@ -12,6 +12,7 @@ const PROXY_FEATURES_FOR_TOKEN_TIME = 'proxy_features_for_token_time';
const STAGE_ENTERED = 'stage-entered' as const; const STAGE_ENTERED = 'stage-entered' as const;
const EXCEEDS_LIMIT = 'exceeds-limit' as const; const EXCEEDS_LIMIT = 'exceeds-limit' as const;
const REQUEST_ORIGIN = 'request_origin' as const; const REQUEST_ORIGIN = 'request_origin' as const;
const ADDON_EVENTS_HANDLED = 'addon-event-handled' as const;
type MetricEvent = type MetricEvent =
| typeof REQUEST_TIME | typeof REQUEST_TIME
@ -71,6 +72,7 @@ export {
STAGE_ENTERED, STAGE_ENTERED,
EXCEEDS_LIMIT, EXCEEDS_LIMIT,
REQUEST_ORIGIN, REQUEST_ORIGIN,
ADDON_EVENTS_HANDLED,
type MetricEvent, type MetricEvent,
type MetricEventPayload, type MetricEventPayload,
emitMetricEvent, emitMetricEvent,

View File

@ -359,6 +359,12 @@ export default class MetricsMonitor {
labelNames: ['resource'], labelNames: ['resource'],
}); });
const addonEventsHandledCounter = createCounter({
name: 'addon_events_handled',
help: 'Events handled by addons and the result.',
labelNames: ['result', 'destination'],
});
async function collectStaticCounters() { async function collectStaticCounters() {
try { try {
const stats = await instanceStatsService.getStats(); const stats = await instanceStatsService.getStats();
@ -906,6 +912,10 @@ export default class MetricsMonitor {
projectEnvironmentsDisabled.increment({ project_id: project }); projectEnvironmentsDisabled.increment({ project_id: project });
}); });
eventBus.on(events.ADDON_EVENTS_HANDLED, ({ result, destination }) => {
addonEventsHandledCounter.increment({ result, destination });
});
await this.configureDbMetrics( await this.configureDbMetrics(
db, db,
eventBus, eventBus,

View File

@ -15,6 +15,7 @@ const ARGS: IAddonConfig = {
unleashUrl: 'http://some-url.com', unleashUrl: 'http://some-url.com',
integrationEventsService: {} as IntegrationEventsService, integrationEventsService: {} as IntegrationEventsService,
flagResolver: {} as IFlagResolver, flagResolver: {} as IFlagResolver,
eventBus: {} as any,
}; };
const definition: IAddonDefinition = { const definition: IAddonDefinition = {

View File

@ -64,7 +64,11 @@ export default class AddonService {
getLogger, getLogger,
server, server,
flagResolver, flagResolver,
}: Pick<IUnleashConfig, 'getLogger' | 'server' | 'flagResolver'>, eventBus,
}: Pick<
IUnleashConfig,
'getLogger' | 'server' | 'flagResolver' | 'eventBus'
>,
tagTypeService: TagTypeService, tagTypeService: TagTypeService,
eventService: EventService, eventService: EventService,
integrationEventsService, integrationEventsService,
@ -83,6 +87,7 @@ export default class AddonService {
unleashUrl: server.unleashUrl, unleashUrl: server.unleashUrl,
integrationEventsService, integrationEventsService,
flagResolver, flagResolver,
eventBus,
}); });
this.sensitiveParams = this.loadSensitiveParams(this.addonProviders); this.sensitiveParams = this.loadSensitiveParams(this.addonProviders);
if (addonStore) { if (addonStore) {

View File

@ -10,6 +10,7 @@ import type { FeatureSearchEnvironmentSchema } from '../openapi/spec/feature-sea
import type { IntegrationEventsService } from '../features/integration-events/integration-events-service'; import type { IntegrationEventsService } from '../features/integration-events/integration-events-service';
import type { IFlagResolver } from './experimental'; import type { IFlagResolver } from './experimental';
import type { Collaborator } from '../features/feature-toggle/types/feature-collaborators-read-model-type'; import type { Collaborator } from '../features/feature-toggle/types/feature-collaborators-read-model-type';
import type { EventEmitter } from 'events';
export type Operator = (typeof ALL_OPERATORS)[number]; export type Operator = (typeof ALL_OPERATORS)[number];
@ -384,6 +385,7 @@ export interface IAddonConfig {
unleashUrl: string; unleashUrl: string;
integrationEventsService: IntegrationEventsService; integrationEventsService: IntegrationEventsService;
flagResolver: IFlagResolver; flagResolver: IFlagResolver;
eventBus: EventEmitter;
} }
export interface IUserWithRole { export interface IUserWithRole {