Removed deprecated events related code

Signed-off-by: Andre Wanlin <awanlin@spotify.com>
This commit is contained in:
Andre Wanlin
2025-02-28 15:46:54 -06:00
parent 85df833fe3
commit ee519c57d9
16 changed files with 11 additions and 462 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/backend-dynamic-feature-service': patch
'@backstage/plugin-events-backend': patch
---
**BREAKING** Removed deprecated events related code
@@ -45,7 +45,6 @@
"test": "backstage-cli package test"
},
"dependencies": {
"@backstage/backend-common": "^0.25.0",
"@backstage/backend-defaults": "workspace:^",
"@backstage/backend-plugin-api": "workspace:^",
"@backstage/cli-common": "workspace:^",
@@ -11,7 +11,6 @@ import { ConfigSchema } from '@backstage/config-loader';
import { DatabaseService } from '@backstage/backend-plugin-api';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import { EventBroker } from '@backstage/plugin-events-node';
import { EventsBackend } from '@backstage/plugin-events-backend';
import { EventsService } from '@backstage/plugin-events-node';
import { HttpPostIngressOptions } from '@backstage/plugin-events-node';
import { IdentityApi } from '@backstage/plugin-auth-node';
@@ -22,7 +21,6 @@ import { PackagePlatform } from '@backstage/cli-node';
import { PackageRole } from '@backstage/cli-node';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { PermissionPolicy } from '@backstage/plugin-permission-node';
import { PluginCacheManager } from '@backstage/backend-common';
import { RootLoggerService } from '@backstage/backend-plugin-api';
import { Router } from 'express';
import { SchedulerService } from '@backstage/backend-plugin-api';
@@ -30,7 +28,6 @@ import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api';
import { ServiceFactory } from '@backstage/backend-plugin-api';
import { ServiceRef } from '@backstage/backend-plugin-api';
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
import { TokenManager } from '@backstage/backend-common';
import { UrlReaderService } from '@backstage/backend-plugin-api';
import { WinstonLoggerOptions } from '@backstage/backend-defaults/rootLogger';
@@ -237,10 +234,7 @@ export interface LegacyBackendPluginInstaller {
// (undocumented)
catalog?(builder: CatalogBuilder, env: LegacyPluginEnvironment): void;
// (undocumented)
events?(
eventsBackend: EventsBackend,
env: LegacyPluginEnvironment,
): HttpPostIngressOptions[];
events?(env: LegacyPluginEnvironment): HttpPostIngressOptions[];
// (undocumented)
kind: 'legacy';
// (undocumented)
@@ -265,12 +259,10 @@ export interface LegacyBackendPluginInstaller {
// @public @deprecated (undocumented)
export type LegacyPluginEnvironment = {
logger: Logger;
cache: PluginCacheManager;
database: DatabaseService;
config: Config;
reader: UrlReaderService;
discovery: DiscoveryService;
tokenManager: TokenManager;
permissions: PermissionEvaluator;
scheduler: SchedulerService;
identity: IdentityApi;
@@ -16,7 +16,6 @@
import { Logger } from 'winston';
import { Config } from '@backstage/config';
import { PluginCacheManager, TokenManager } from '@backstage/backend-common';
import { Router } from 'express';
import { IdentityApi } from '@backstage/plugin-auth-node';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
@@ -38,7 +37,6 @@ import { PackagePlatform, PackageRole } from '@backstage/cli-node';
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
import { IndexBuilder } from '@backstage/plugin-search-backend-node';
import { EventsBackend } from '@backstage/plugin-events-backend';
import { PermissionPolicy } from '@backstage/plugin-permission-node';
import { ScannedPluginPackage } from '../scanner';
@@ -56,12 +54,10 @@ import { ScannedPluginPackage } from '../scanner';
*/
export type LegacyPluginEnvironment = {
logger: Logger;
cache: PluginCacheManager;
database: DatabaseService;
config: Config;
reader: UrlReaderService;
discovery: DiscoveryService;
tokenManager: TokenManager;
permissions: PermissionEvaluator;
scheduler: SchedulerService;
identity: IdentityApi;
@@ -169,10 +165,7 @@ export interface LegacyBackendPluginInstaller {
schedule: SchedulerServiceTaskRunner,
env: LegacyPluginEnvironment,
): void;
events?(
eventsBackend: EventsBackend,
env: LegacyPluginEnvironment,
): HttpPostIngressOptions[];
events?(env: LegacyPluginEnvironment): HttpPostIngressOptions[];
permissions?: {
policy?: PermissionPolicy;
};
+1 -6
View File
@@ -49,7 +49,6 @@ import permission from './plugins/permission';
import { PluginEnvironment } from './types';
import { ServerPermissionClient } from '@backstage/plugin-permission-node';
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
import { DefaultEventBroker } from '@backstage/plugin-events-backend';
import { DefaultEventsService } from '@backstage/plugin-events-node';
import { DefaultSignalsService } from '@backstage/plugin-signals-node';
import { UrlReaders } from '@backstage/backend-defaults/urlReader';
@@ -76,10 +75,7 @@ function makeCreateEnv(config: Config) {
});
const eventsService = DefaultEventsService.create({ logger: root, config });
const eventBroker = new DefaultEventBroker(
root.child({ type: 'plugin' }),
eventsService,
);
const signalsService = DefaultSignalsService.create({
events: eventsService,
});
@@ -101,7 +97,6 @@ function makeCreateEnv(config: Config) {
database,
config,
reader,
eventBroker,
events: eventsService,
discovery,
tokenManager,
+1 -5
View File
@@ -19,7 +19,7 @@ import { Config } from '@backstage/config';
import { PluginCacheManager, TokenManager } from '@backstage/backend-common';
import { IdentityApi } from '@backstage/plugin-auth-node';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { EventBroker, EventsService } from '@backstage/plugin-events-node';
import { EventsService } from '@backstage/plugin-events-node';
import { SignalsService } from '@backstage/plugin-signals-node';
import {
UrlReaderService,
@@ -39,10 +39,6 @@ export type PluginEnvironment = {
permissions: PermissionEvaluator;
scheduler: SchedulerService;
identity: IdentityApi;
/**
* @deprecated use `events` instead
*/
eventBroker: EventBroker;
events: EventsService;
signals: SignalsService;
};
-68
View File
@@ -26,58 +26,6 @@ yarn --cwd packages/backend add @backstage/plugin-events-backend
backend.add(import('@backstage/plugin-events-backend'));
```
### Legacy Backend System
```ts
// packages/backend/src/plugins/events.ts
import { HttpPostIngressEventPublisher } from '@backstage/plugin-events-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const eventsRouter = Router();
const http = HttpPostIngressEventPublisher.fromConfig({
config: env.config,
events: env.events,
logger: env.logger,
});
http.bind(eventsRouter);
return eventsRouter;
}
```
### Event-based Entity Providers
You can implement the `EventSubscriber` interface on an `EntityProviders` to allow it to handle events from other plugins e.g. the event backend plugin
mentioned above.
Assuming you have configured the `eventBroker` into the `PluginEnvironment` you can pass the broker to the entity provider for it to subscribe.
```diff
// packages/backend/src/plugins/catalog.ts
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
+import { DemoEventBasedEntityProvider } from './DemoEventBasedEntityProvider';
import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const builder = await CatalogBuilder.create(env);
builder.addProcessor(new ScaffolderEntitiesProcessor());
+ const demoProvider = new DemoEventBasedEntityProvider({ logger: env.logger, topics: ['example'], eventBroker: env.eventBroker });
+ builder.addEntityProvider(demoProvider);
const { processingEngine, router } = await builder.build();
await processingEngine.start();
return router;
}
```
## Configuration
In order to create HTTP endpoints to receive events for a certain
@@ -181,19 +129,3 @@ export const eventsModuleYourFeature = createBackendModule({
We have the following default parsers:
- `application/json`
#### Legacy Backend System
```ts
const http = HttpPostIngressEventPublisher.fromConfig({
config: env.config,
events: env.events,
ingresses: {
yourTopic: {
validator: yourValidator,
},
},
logger: env.logger,
});
http.bind(router);
```
+1 -3
View File
@@ -53,7 +53,6 @@
"test": "backstage-cli package test"
},
"dependencies": {
"@backstage/backend-common": "^0.25.0",
"@backstage/backend-openapi-utils": "workspace:^",
"@backstage/backend-plugin-api": "workspace:^",
"@backstage/config": "workspace:^",
@@ -64,8 +63,7 @@
"content-type": "^1.0.5",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"knex": "^3.0.0",
"winston": "^3.2.1"
"knex": "^3.0.0"
},
"devDependencies": {
"@backstage/backend-app-api": "workspace:^",
-33
View File
@@ -5,45 +5,12 @@
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';
import { Config } from '@backstage/config';
import { EventBroker } from '@backstage/plugin-events-node';
import { EventParams } from '@backstage/plugin-events-node';
import { EventPublisher } from '@backstage/plugin-events-node';
import { EventsService } from '@backstage/plugin-events-node';
import { EventSubscriber } from '@backstage/plugin-events-node';
import express from 'express';
import { HttpBodyParser } from '@backstage/plugin-events-node';
import { HttpPostIngressOptions } from '@backstage/plugin-events-node';
import { Logger } from 'winston';
import { LoggerService } from '@backstage/backend-plugin-api';
// @public @deprecated
export class DefaultEventBroker implements EventBroker {
// @deprecated
constructor(logger: LoggerService, events?: EventsService);
// (undocumented)
publish(params: EventParams): Promise<void>;
// (undocumented)
subscribe(
...subscribers: Array<EventSubscriber | Array<EventSubscriber>>
): void;
}
// @public @deprecated
export class EventsBackend {
constructor(logger: Logger);
// (undocumented)
addPublishers(
...publishers: Array<EventPublisher | Array<EventPublisher>>
): EventsBackend;
// (undocumented)
addSubscribers(
...subscribers: Array<EventSubscriber | Array<EventSubscriber>>
): EventsBackend;
// (undocumented)
setEventBroker(eventBroker: EventBroker): EventsBackend;
start(): Promise<void>;
}
// @public
const eventsPlugin: BackendFeature;
export default eventsPlugin;
-18
View File
@@ -1,18 +0,0 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { EventsBackend } from './service/EventsBackend';
export { DefaultEventBroker } from './service/DefaultEventBroker';
-1
View File
@@ -21,5 +21,4 @@
*/
export { eventsPlugin as default } from './service/EventsPlugin';
export * from './deprecated';
export { HttpPostIngressEventPublisher } from './service/http';
@@ -1,114 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TestEventSubscriber } from '@backstage/plugin-events-backend-test-utils';
import { EventParams, EventSubscriber } from '@backstage/plugin-events-node';
import { DefaultEventBroker } from './DefaultEventBroker';
import { mockServices } from '@backstage/backend-test-utils';
const logger = mockServices.logger.mock();
describe('DefaultEventBroker', () => {
it('passes events to interested subscribers', () => {
const subscriber1 = new TestEventSubscriber('test1', ['topicA', 'topicB']);
const subscriber2 = new TestEventSubscriber('test2', ['topicB', 'topicC']);
const eventBroker = new DefaultEventBroker(logger);
eventBroker.subscribe(subscriber1);
eventBroker.subscribe(subscriber2);
eventBroker.publish({ topic: 'topicA', eventPayload: { test: 'topicA' } });
eventBroker.publish({ topic: 'topicB', eventPayload: { test: 'topicB' } });
eventBroker.publish({ topic: 'topicC', eventPayload: { test: 'topicC' } });
eventBroker.publish({ topic: 'topicD', eventPayload: { test: 'topicD' } });
expect(Object.keys(subscriber1.receivedEvents)).toEqual([
'topicA',
'topicB',
]);
expect(subscriber1.receivedEvents.topicA.length).toEqual(1);
expect(subscriber1.receivedEvents.topicA[0]).toEqual({
topic: 'topicA',
eventPayload: { test: 'topicA' },
});
expect(subscriber1.receivedEvents.topicB.length).toEqual(1);
expect(subscriber1.receivedEvents.topicB[0]).toEqual({
topic: 'topicB',
eventPayload: { test: 'topicB' },
});
expect(Object.keys(subscriber2.receivedEvents)).toEqual([
'topicB',
'topicC',
]);
expect(subscriber2.receivedEvents.topicB.length).toEqual(1);
expect(subscriber2.receivedEvents.topicB[0]).toEqual({
topic: 'topicB',
eventPayload: { test: 'topicB' },
});
expect(subscriber2.receivedEvents.topicC.length).toEqual(1);
expect(subscriber2.receivedEvents.topicC[0]).toEqual({
topic: 'topicC',
eventPayload: { test: 'topicC' },
});
});
it('logs errors from subscribers', async () => {
const topic = 'testTopic';
const subscriber1 = new (class Subscriber1 implements EventSubscriber {
supportsEventTopics() {
return [topic];
}
async onEvent(event: EventParams) {
throw new Error(`NOPE ${event.eventPayload}`);
}
})();
const subscriber2 = new (class Subscriber2 implements EventSubscriber {
supportsEventTopics() {
return [topic];
}
async onEvent(event: EventParams) {
throw new Error(`NOPE ${event.eventPayload}`);
}
})();
const warnSpy = jest.spyOn(logger, 'warn');
const eventBroker = new DefaultEventBroker(logger);
eventBroker.subscribe(subscriber1);
await eventBroker.publish({ topic, eventPayload: '1' });
expect(warnSpy).toHaveBeenCalledTimes(1);
expect(warnSpy).toHaveBeenCalledWith(
'Subscriber "Subscriber1" failed to process event for topic "testTopic"',
new Error('NOPE 1'),
);
eventBroker.subscribe(subscriber2);
await eventBroker.publish({ topic, eventPayload: '2' });
// With two subscribers we should not halt on the first error but call all subscribers
expect(warnSpy).toHaveBeenCalledTimes(3);
expect(warnSpy).toHaveBeenCalledWith(
'Subscriber "Subscriber1" failed to process event for topic "testTopic"',
new Error('NOPE 2'),
);
expect(warnSpy).toHaveBeenCalledWith(
'Subscriber "Subscriber2" failed to process event for topic "testTopic"',
new Error('NOPE 2'),
);
});
});
@@ -1,64 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { LoggerService } from '@backstage/backend-plugin-api';
import {
DefaultEventsService,
EventBroker,
EventParams,
EventsService,
EventSubscriber,
} from '@backstage/plugin-events-node';
/**
* In process event broker which will pass the event to all registered subscribers
* interested in it.
* Events will not be persisted in any form.
*
* @public
* @deprecated use `DefaultEventsService` from `@backstage/plugin-events-node` instead
*/
export class DefaultEventBroker implements EventBroker {
private readonly events: EventsService;
/**
*
* @param logger - logger
* @param events - replacement that gets wrapped to support not yet migrated implementations.
* An instance can be passed (required for a mixed mode), otherwise a new instance gets created internally.
* @deprecated use `DefaultEventsService` directly instead
*/
constructor(logger: LoggerService, events?: EventsService) {
this.events =
events ?? DefaultEventsService.create({ logger, useEventBus: 'never' });
}
async publish(params: EventParams): Promise<void> {
return this.events.publish(params);
}
subscribe(
...subscribers: Array<EventSubscriber | Array<EventSubscriber>>
): void {
subscribers.flat().forEach(async subscriber => {
await this.events.subscribe({
id: subscriber.constructor.name,
topics: subscriber.supportsEventTopics(),
onEvent: subscriber.onEvent.bind(subscriber),
});
});
}
}
@@ -1,61 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
TestEventBroker,
TestEventPublisher,
TestEventSubscriber,
} from '@backstage/plugin-events-backend-test-utils';
import { EventsBackend } from './EventsBackend';
import { mockServices } from '@backstage/backend-test-utils';
import { loggerToWinstonLogger } from '@backstage/backend-common';
const logger = mockServices.logger.mock();
describe('EventsBackend', () => {
it('wires up all components', async () => {
const eventBroker = new TestEventBroker();
const publisher1 = new TestEventPublisher();
const publisher2 = new TestEventPublisher();
await new EventsBackend(loggerToWinstonLogger(logger))
.setEventBroker(eventBroker)
.addPublishers(publisher1, [publisher2])
.addSubscribers(new TestEventSubscriber('one', ['topicA']), [
new TestEventSubscriber('two', ['topicA', 'topicB']),
])
.start();
await eventBroker.publish({
topic: 'topicA',
eventPayload: { test: 'payload' },
});
expect(eventBroker.published.length).toEqual(1);
expect(eventBroker.published[0].topic).toEqual('topicA');
expect(eventBroker.published[0].eventPayload).toEqual({ test: 'payload' });
expect(eventBroker.subscribed.length).toEqual(2);
expect(
eventBroker.subscribed.map(
sub => (sub as unknown as TestEventSubscriber).name,
),
).toEqual(['one', 'two']);
expect(publisher1.eventBroker).toBe(eventBroker);
expect(publisher2.eventBroker).toBe(eventBroker);
});
});
@@ -1,68 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
EventBroker,
EventPublisher,
EventSubscriber,
} from '@backstage/plugin-events-node';
import { Logger } from 'winston';
import { DefaultEventBroker } from './DefaultEventBroker';
/**
* A builder that helps wire up all component parts of the event management.
*
* @public
* @deprecated `EventBroker`, `EventPublisher`, and `EventSubscriber` got replaced by `EventsService` and its methods.
*/
export class EventsBackend {
private eventBroker: EventBroker;
private publishers: EventPublisher[] = [];
private subscribers: EventSubscriber[] = [];
constructor(logger: Logger) {
this.eventBroker = new DefaultEventBroker(logger);
}
setEventBroker(eventBroker: EventBroker): EventsBackend {
this.eventBroker = eventBroker;
return this;
}
addPublishers(
...publishers: Array<EventPublisher | Array<EventPublisher>>
): EventsBackend {
this.publishers.push(...publishers.flat());
return this;
}
addSubscribers(
...subscribers: Array<EventSubscriber | Array<EventSubscriber>>
): EventsBackend {
this.subscribers.push(...subscribers.flat());
return this;
}
/**
* Wires up and returns all component parts of the event management.
*/
async start(): Promise<void> {
this.eventBroker.subscribe(this.subscribers);
this.publishers.forEach(publisher =>
publisher.setEventBroker(this.eventBroker),
);
}
}
-3
View File
@@ -3694,7 +3694,6 @@ __metadata:
resolution: "@backstage/backend-dynamic-feature-service@workspace:packages/backend-dynamic-feature-service"
dependencies:
"@backstage/backend-app-api": "workspace:^"
"@backstage/backend-common": ^0.25.0
"@backstage/backend-defaults": "workspace:^"
"@backstage/backend-plugin-api": "workspace:^"
"@backstage/backend-test-utils": "workspace:^"
@@ -6754,7 +6753,6 @@ __metadata:
resolution: "@backstage/plugin-events-backend@workspace:plugins/events-backend"
dependencies:
"@backstage/backend-app-api": "workspace:^"
"@backstage/backend-common": ^0.25.0
"@backstage/backend-defaults": "workspace:^"
"@backstage/backend-openapi-utils": "workspace:^"
"@backstage/backend-plugin-api": "workspace:^"
@@ -6773,7 +6771,6 @@ __metadata:
express-promise-router: ^4.1.0
knex: ^3.0.0
supertest: ^7.0.0
winston: ^3.2.1
languageName: unknown
linkType: soft