@backstage/plugin-events-backend-module-aws-sqs 0.2.15 → 0.3.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,24 +1,47 @@
1
1
  # @backstage/plugin-events-backend-module-aws-sqs
2
2
 
3
- ## 0.2.15
3
+ ## 0.3.0-next.0
4
4
 
5
- ### Patch Changes
5
+ ### Minor Changes
6
6
 
7
- - Updated dependencies
8
- - @backstage/backend-common@0.21.2
9
- - @backstage/backend-tasks@0.5.17
10
- - @backstage/backend-plugin-api@0.6.12
11
- - @backstage/plugin-events-node@0.2.21
7
+ - 132d672: BREAKING CHANGE: Migrate `AwsSqsConsumingEventPublisher` and its backend module to use `EventsService`.
8
+
9
+ Uses the `EventsService` instead of `EventBroker` at `AwsSqsConsumingEventPublisher`,
10
+ dropping the use of `EventPublisher` including `setEventBroker(..)`.
11
+
12
+ Now, `AwsSqsConsumingEventPublisher.fromConfig` requires `events: EventsService` as option.
12
13
 
13
- ## 0.2.14
14
+ ```diff
15
+ const sqs = AwsSqsConsumingEventPublisher.fromConfig({
16
+ config: env.config,
17
+ + events: env.events,
18
+ logger: env.logger,
19
+ scheduler: env.scheduler,
20
+ });
21
+ + await Promise.all(sqs.map(publisher => publisher.start()));
22
+
23
+ // e.g. at packages/backend/src/plugins/events.ts
24
+ - await new EventsBackend(env.logger)
25
+ - .setEventBroker(env.eventBroker)
26
+ - .addPublishers(sqs)
27
+ - .start();
28
+
29
+ // or for other kinds of setups
30
+ - await Promise.all(sqs.map(publisher => publisher.setEventBroker(eventBroker)));
31
+ ```
32
+
33
+ `eventsModuleAwsSqsConsumingEventPublisher` uses the `eventsServiceRef` as dependency,
34
+ instead of `eventsExtensionPoint`.
14
35
 
15
36
  ### Patch Changes
16
37
 
17
38
  - Updated dependencies
18
- - @backstage/backend-common@0.21.1
19
- - @backstage/backend-tasks@0.5.16
20
- - @backstage/backend-plugin-api@0.6.11
21
- - @backstage/plugin-events-node@0.2.20
39
+ - @backstage/plugin-events-node@0.3.0-next.0
40
+ - @backstage/backend-common@0.21.3-next.0
41
+ - @backstage/backend-plugin-api@0.6.13-next.0
42
+ - @backstage/backend-tasks@0.5.18-next.0
43
+ - @backstage/config@1.1.2-next.0
44
+ - @backstage/types@1.1.1
22
45
 
23
46
  ## 0.2.13
24
47
 
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
- # events-backend-module-aws-sqs
1
+ # `@backstage/plugins-events-backend-module-aws-sqs`
2
2
 
3
- Welcome to the `events-backend-module-aws-sqs` backend plugin!
3
+ Welcome to the `events-backend-module-aws-sqs` backend module!
4
4
 
5
- This plugin is a module for the `events-backend` backend plugin
6
- and extends it with an `AwsSqsConsumingEventPublisher`.
5
+ This package is a module for the `events-backend` backend plugin
6
+ and extends the events system with an `AwsSqsConsumingEventPublisher`.
7
7
 
8
- This event publisher will allow you to receive events from
9
- an AWS SQS queue and will publish these to the used event broker.
8
+ This event publisher will allow you to receive events from an AWS SQS queue
9
+ and will publish these to the used `EventsService` implementation.
10
10
 
11
11
  ## Configuration
12
12
 
@@ -32,15 +32,43 @@ events:
32
32
 
33
33
  ## Installation
34
34
 
35
- 1. Install the [`events-backend` plugin](../events-backend/README.md).
36
- 2. Install this module
37
- 3. Add your configuration.
35
+ 1. Install this module
36
+ 2. Add your configuration.
38
37
 
39
38
  ```bash
40
39
  # From your Backstage root directory
41
40
  yarn --cwd packages/backend add @backstage/plugin-events-backend-module-aws-sqs
42
41
  ```
43
42
 
44
- ```ts title="packages/backend/src/index.ts"
43
+ ```ts
44
+ // packages/backend/src/index.ts
45
45
  backend.add(import('@backstage/plugin-events-backend-module-aws-sqs/alpha'));
46
46
  ```
47
+
48
+ ### Legacy Backend System
49
+
50
+ ```ts
51
+ // packages/backend/src/plugins/events.ts
52
+ // ...
53
+ import { AwsSqsConsumingEventPublisher } from '@backstage/plugin-events-backend-module-aws-sqs';
54
+ import { Router } from 'express';
55
+ import { PluginEnvironment } from '../types';
56
+
57
+ export default async function createPlugin(
58
+ env: PluginEnvironment,
59
+ ): Promise<Router> {
60
+ const eventsRouter = Router();
61
+
62
+ // ...
63
+
64
+ const sqs = AwsSqsConsumingEventPublisher.fromConfig({
65
+ config: env.config,
66
+ events: env.events,
67
+ logger: env.logger,
68
+ scheduler: env.scheduler,
69
+ });
70
+ await Promise.all(sqs.map(publisher => publisher.start()));
71
+
72
+ return eventsRouter;
73
+ }
74
+ ```
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-events-backend-module-aws-sqs",
3
- "version": "0.2.15",
3
+ "version": "0.3.0-next.0",
4
4
  "main": "../dist/alpha.cjs.js",
5
5
  "types": "../dist/alpha.d.ts"
6
6
  }
package/dist/alpha.cjs.js CHANGED
@@ -3,9 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var backendPluginApi = require('@backstage/backend-plugin-api');
6
- var backendCommon = require('@backstage/backend-common');
7
- var alpha = require('@backstage/plugin-events-node/alpha');
8
- var AwsSqsConsumingEventPublisher = require('./cjs/AwsSqsConsumingEventPublisher-034938f3.cjs.js');
6
+ var pluginEventsNode = require('@backstage/plugin-events-node');
7
+ var AwsSqsConsumingEventPublisher = require('./cjs/AwsSqsConsumingEventPublisher-8341998e.cjs.js');
9
8
  require('@aws-sdk/client-sqs');
10
9
  require('luxon');
11
10
 
@@ -16,18 +15,18 @@ const eventsModuleAwsSqsConsumingEventPublisher = backendPluginApi.createBackend
16
15
  env.registerInit({
17
16
  deps: {
18
17
  config: backendPluginApi.coreServices.rootConfig,
19
- events: alpha.eventsExtensionPoint,
18
+ events: pluginEventsNode.eventsServiceRef,
20
19
  logger: backendPluginApi.coreServices.logger,
21
20
  scheduler: backendPluginApi.coreServices.scheduler
22
21
  },
23
22
  async init({ config, events, logger, scheduler }) {
24
- const winstonLogger = backendCommon.loggerToWinstonLogger(logger);
25
23
  const sqs = AwsSqsConsumingEventPublisher.AwsSqsConsumingEventPublisher.fromConfig({
26
24
  config,
27
- logger: winstonLogger,
25
+ events,
26
+ logger,
28
27
  scheduler
29
28
  });
30
- events.addPublishers(sqs);
29
+ await Promise.all(sqs.map((publisher) => publisher.start()));
31
30
  }
32
31
  });
33
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.cjs.js","sources":["../src/service/eventsModuleAwsSqsConsumingEventPublisher.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha';\nimport { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEventPublisher';\n\n/**\n * AWS SQS module for the Events plugin.\n *\n * @alpha\n */\nexport const eventsModuleAwsSqsConsumingEventPublisher = createBackendModule({\n pluginId: 'events',\n moduleId: 'aws-sqs-consuming-event-publisher',\n register(env) {\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n events: eventsExtensionPoint,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n },\n async init({ config, events, logger, scheduler }) {\n const winstonLogger = loggerToWinstonLogger(logger);\n const sqs = AwsSqsConsumingEventPublisher.fromConfig({\n config: config,\n logger: winstonLogger,\n scheduler: scheduler,\n });\n\n events.addPublishers(sqs);\n },\n });\n },\n});\n"],"names":["createBackendModule","coreServices","eventsExtensionPoint","loggerToWinstonLogger","AwsSqsConsumingEventPublisher"],"mappings":";;;;;;;;;;;AA6BO,MAAM,4CAA4CA,oCAAoB,CAAA;AAAA,EAC3E,QAAU,EAAA,QAAA;AAAA,EACV,QAAU,EAAA,mCAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,MAAQ,EAAAC,0BAAA;AAAA,QACR,QAAQD,6BAAa,CAAA,MAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,OAC1B;AAAA,MACA,MAAM,IAAK,CAAA,EAAE,QAAQ,MAAQ,EAAA,MAAA,EAAQ,WAAa,EAAA;AAChD,QAAM,MAAA,aAAA,GAAgBE,oCAAsB,MAAM,CAAA,CAAA;AAClD,QAAM,MAAA,GAAA,GAAMC,4DAA8B,UAAW,CAAA;AAAA,UACnD,MAAA;AAAA,UACA,MAAQ,EAAA,aAAA;AAAA,UACR,SAAA;AAAA,SACD,CAAA,CAAA;AAED,QAAA,MAAA,CAAO,cAAc,GAAG,CAAA,CAAA;AAAA,OAC1B;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"alpha.cjs.js","sources":["../src/service/eventsModuleAwsSqsConsumingEventPublisher.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEventPublisher';\n\n/**\n * AWS SQS module for the Events plugin.\n *\n * @alpha\n */\nexport const eventsModuleAwsSqsConsumingEventPublisher = createBackendModule({\n pluginId: 'events',\n moduleId: 'aws-sqs-consuming-event-publisher',\n register(env) {\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n events: eventsServiceRef,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n },\n async init({ config, events, logger, scheduler }) {\n const sqs = AwsSqsConsumingEventPublisher.fromConfig({\n config,\n events,\n logger,\n scheduler,\n });\n\n await Promise.all(sqs.map(publisher => publisher.start()));\n },\n });\n },\n});\n"],"names":["createBackendModule","coreServices","eventsServiceRef","AwsSqsConsumingEventPublisher"],"mappings":";;;;;;;;;;AA4BO,MAAM,4CAA4CA,oCAAoB,CAAA;AAAA,EAC3E,QAAU,EAAA,QAAA;AAAA,EACV,QAAU,EAAA,mCAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,QAAQC,6BAAa,CAAA,UAAA;AAAA,QACrB,MAAQ,EAAAC,iCAAA;AAAA,QACR,QAAQD,6BAAa,CAAA,MAAA;AAAA,QACrB,WAAWA,6BAAa,CAAA,SAAA;AAAA,OAC1B;AAAA,MACA,MAAM,IAAK,CAAA,EAAE,QAAQ,MAAQ,EAAA,MAAA,EAAQ,WAAa,EAAA;AAChD,QAAM,MAAA,GAAA,GAAME,4DAA8B,UAAW,CAAA;AAAA,UACnD,MAAA;AAAA,UACA,MAAA;AAAA,UACA,MAAA;AAAA,UACA,SAAA;AAAA,SACD,CAAA,CAAA;AAED,QAAM,MAAA,OAAA,CAAQ,IAAI,GAAI,CAAA,GAAA,CAAI,eAAa,SAAU,CAAA,KAAA,EAAO,CAAC,CAAA,CAAA;AAAA,OAC3D;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
@@ -73,8 +73,9 @@ var __publicField = (obj, key, value) => {
73
73
  return value;
74
74
  };
75
75
  class AwsSqsConsumingEventPublisher {
76
- constructor(logger, scheduler, config) {
76
+ constructor(logger, events, scheduler, config) {
77
77
  this.logger = logger;
78
+ this.events = events;
78
79
  this.scheduler = scheduler;
79
80
  __publicField(this, "topic");
80
81
  __publicField(this, "receiveParams");
@@ -82,7 +83,6 @@ class AwsSqsConsumingEventPublisher {
82
83
  __publicField(this, "queueUrl");
83
84
  __publicField(this, "taskTimeoutSeconds");
84
85
  __publicField(this, "waitTimeAfterEmptyReceiveMs");
85
- __publicField(this, "eventBroker");
86
86
  var _a;
87
87
  this.topic = config.topic;
88
88
  this.receiveParams = {
@@ -102,13 +102,14 @@ class AwsSqsConsumingEventPublisher {
102
102
  }
103
103
  static fromConfig(env) {
104
104
  return readConfig(env.config).map(
105
- (config) => new AwsSqsConsumingEventPublisher(env.logger, env.scheduler, config)
105
+ (config) => new AwsSqsConsumingEventPublisher(
106
+ env.logger,
107
+ env.events,
108
+ env.scheduler,
109
+ config
110
+ )
106
111
  );
107
112
  }
108
- async setEventBroker(eventBroker) {
109
- this.eventBroker = eventBroker;
110
- return this.start();
111
- }
112
113
  async start() {
113
114
  const id = `events.awsSqs.publisher:${this.topic}`;
114
115
  const logger = this.logger.child({
@@ -183,7 +184,7 @@ class AwsSqsConsumingEventPublisher {
183
184
  metadata[key] = value;
184
185
  }
185
186
  });
186
- this.eventBroker.publish({
187
+ this.events.publish({
187
188
  topic: this.topic,
188
189
  eventPayload,
189
190
  metadata
@@ -205,4 +206,4 @@ class AwsSqsConsumingEventPublisher {
205
206
  }
206
207
 
207
208
  exports.AwsSqsConsumingEventPublisher = AwsSqsConsumingEventPublisher;
208
- //# sourceMappingURL=AwsSqsConsumingEventPublisher-034938f3.cjs.js.map
209
+ //# sourceMappingURL=AwsSqsConsumingEventPublisher-8341998e.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AwsSqsConsumingEventPublisher-8341998e.cjs.js","sources":["../../src/publisher/config.ts","../../src/publisher/AwsSqsConsumingEventPublisher.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { HumanDuration, JsonObject } from '@backstage/types';\nimport { Duration } from 'luxon';\n\nconst CONFIG_PREFIX_MODULE = 'events.modules.awsSqs.';\nconst CONFIG_PREFIX_PUBLISHER = `${CONFIG_PREFIX_MODULE}awsSqsConsumingEventPublisher.`;\nconst DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE = { minutes: 1 };\nconst MAX_WAIT_SECONDS = 20;\n\nexport interface AwsSqsEventSourceConfig {\n pollingWaitTime: Duration;\n queueUrl: string;\n region: string;\n timeout: Duration;\n topic: string;\n visibilityTimeout?: Duration;\n waitTimeAfterEmptyReceive: Duration;\n endpoint?: string;\n}\n\n// TODO(pjungermann): validation could be improved similar to `convertToHumanDuration` at @backstage/backend-tasks\nfunction readOptionalHumanDuration(\n config: Config,\n key: string,\n): HumanDuration | undefined {\n return config.getOptional<JsonObject>(key) as HumanDuration;\n}\n\nfunction readOptionalDuration(\n config: Config,\n key: string,\n): Duration | undefined {\n const duration = readOptionalHumanDuration(config, key);\n return duration ? Duration.fromObject(duration) : undefined;\n}\n\nexport function readConfig(config: Config): AwsSqsEventSourceConfig[] {\n const key = `${CONFIG_PREFIX_PUBLISHER}topics`;\n const topics = config.getOptionalConfig(key);\n\n return (\n topics?.keys()?.map(topic => {\n const topicConfig = topics.getConfig(topic);\n const keyPrefix = `${key}.${topic}.`;\n\n // queue config:\n const pollingWaitTime = Duration.fromObject(\n readOptionalHumanDuration(topicConfig, 'queue.waitTime') ?? {\n seconds: MAX_WAIT_SECONDS,\n },\n );\n if (\n pollingWaitTime.valueOf() < 0 ||\n pollingWaitTime.as('seconds') > MAX_WAIT_SECONDS\n ) {\n throw new Error(\n `${keyPrefix}queue.waitTime must be within 0..${MAX_WAIT_SECONDS} seconds.`,\n );\n }\n const queueUrl = topicConfig.getString('queue.url');\n const region = topicConfig.getString('queue.region');\n const endpoint = topicConfig.getOptionalString('queue.endpoint');\n const visibilityTimeout = readOptionalDuration(\n topicConfig,\n 'queue.visibilityTimeout',\n );\n\n // task:\n const waitTimeAfterEmptyReceive = Duration.fromObject(\n readOptionalHumanDuration(topicConfig, 'waitTimeAfterEmptyReceive') ??\n DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE,\n );\n if (waitTimeAfterEmptyReceive.valueOf() < 0) {\n throw new Error(\n `The ${keyPrefix}waitTimeAfterEmptyReceive must not be negative.`,\n );\n }\n const timeout =\n readOptionalDuration(topicConfig, 'timeout') ??\n pollingWaitTime\n .plus(waitTimeAfterEmptyReceive)\n .plus(Duration.fromObject({ seconds: 180 }));\n if (\n timeout.valueOf() <=\n pollingWaitTime.valueOf() + waitTimeAfterEmptyReceive.valueOf()\n ) {\n throw new Error(\n `The ${keyPrefix}timeout must be greater than ${keyPrefix}queue.waitTime + ${keyPrefix}waitTimeAfterEmptyReceive.`,\n );\n }\n\n return {\n pollingWaitTime,\n queueUrl,\n endpoint,\n region,\n timeout,\n topic,\n visibilityTimeout,\n waitTimeAfterEmptyReceive,\n };\n }) ?? []\n );\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DeleteMessageBatchCommand,\n Message,\n ReceiveMessageCommand,\n ReceiveMessageCommandInput,\n SQSClient,\n} from '@aws-sdk/client-sqs';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\nimport { EventsService } from '@backstage/plugin-events-node';\nimport { AwsSqsEventSourceConfig, readConfig } from './config';\n\n/**\n * Publishes events received from an AWS SQS queue.\n * The message payload will be used as event payload and passed to registered subscribers.\n *\n * @public\n */\n// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.)\nexport class AwsSqsConsumingEventPublisher {\n private readonly topic: string;\n private readonly receiveParams: ReceiveMessageCommandInput;\n private readonly sqs: SQSClient;\n private readonly queueUrl: string;\n private readonly taskTimeoutSeconds: number;\n private readonly waitTimeAfterEmptyReceiveMs;\n\n static fromConfig(env: {\n config: Config;\n events: EventsService;\n logger: LoggerService;\n scheduler: PluginTaskScheduler;\n }): AwsSqsConsumingEventPublisher[] {\n return readConfig(env.config).map(\n config =>\n new AwsSqsConsumingEventPublisher(\n env.logger,\n env.events,\n env.scheduler,\n config,\n ),\n );\n }\n\n private constructor(\n private readonly logger: LoggerService,\n private readonly events: EventsService,\n private readonly scheduler: PluginTaskScheduler,\n config: AwsSqsEventSourceConfig,\n ) {\n this.topic = config.topic;\n\n this.receiveParams = {\n MaxNumberOfMessages: 10,\n MessageAttributeNames: ['All'],\n QueueUrl: config.queueUrl,\n VisibilityTimeout: config.visibilityTimeout?.as('seconds'),\n WaitTimeSeconds: config.pollingWaitTime.as('seconds'),\n };\n\n this.sqs = new SQSClient({\n region: config.region,\n endpoint: config.endpoint,\n });\n this.queueUrl = config.queueUrl;\n\n this.taskTimeoutSeconds = config.timeout.as('seconds');\n this.waitTimeAfterEmptyReceiveMs =\n config.waitTimeAfterEmptyReceive.as('milliseconds');\n }\n\n async start(): Promise<void> {\n const id = `events.awsSqs.publisher:${this.topic}`;\n const logger = this.logger.child({\n class: AwsSqsConsumingEventPublisher.prototype.constructor.name,\n taskId: id,\n });\n\n await this.scheduler.scheduleTask({\n id: id,\n frequency: { seconds: 0 },\n timeout: { seconds: this.taskTimeoutSeconds },\n scope: 'local',\n fn: async () => {\n try {\n const numMessages = await this.consumeMessages();\n if (numMessages === 0) {\n await this.sleep(this.waitTimeAfterEmptyReceiveMs);\n }\n } catch (error) {\n logger.error('Failed to consume AWS SQS messages', error);\n }\n },\n });\n }\n\n private async deleteMessages(messages?: Message[]): Promise<void> {\n if (!messages || messages.length === 0) {\n return;\n }\n\n const deleteParams = {\n QueueUrl: this.queueUrl,\n Entries: messages.map((message, index) => {\n return {\n Id: message.MessageId ?? `message-${index}`,\n ReceiptHandle: message.ReceiptHandle,\n };\n }),\n };\n\n try {\n const result = await this.sqs.send(\n new DeleteMessageBatchCommand(deleteParams),\n );\n if (result.Failed && result.Failed.length > 0) {\n this.logger.error(\n `Failed to delete ${result.Failed!.length} of ${\n messages.length\n } messages from AWS SQS ${this.queueUrl}. First: ${\n result.Failed[0].Message\n }`,\n );\n }\n } catch (error) {\n this.logger.error(\n `Failed to delete message from AWS SQS ${this.queueUrl}`,\n error,\n );\n }\n }\n\n private async consumeMessages(): Promise<number> {\n try {\n const data = await this.sqs.send(\n new ReceiveMessageCommand(this.receiveParams),\n );\n\n data.Messages?.forEach(message => {\n const eventPayload = JSON.parse(message.Body!);\n\n const metadata: Record<string, string | string[]> = {};\n Object.keys(message.MessageAttributes ?? {}).forEach(key => {\n const attrValue = message.MessageAttributes![key];\n if (\n !attrValue ||\n !attrValue.DataType ||\n !['String', 'Number'].includes(attrValue.DataType)\n ) {\n return;\n }\n\n const value = attrValue.StringListValues ?? attrValue.StringValue;\n if (value !== undefined) {\n metadata[key] = value;\n }\n });\n\n this.events.publish({\n topic: this.topic,\n eventPayload,\n metadata,\n });\n });\n await this.deleteMessages(data.Messages);\n return data.Messages?.length ?? 0;\n } catch (error) {\n this.logger.error(\n `Failed to receive events from AWS SQS ${this.queueUrl}`,\n error,\n );\n return 0;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise<void>(resolve => setTimeout(resolve, ms));\n }\n}\n"],"names":["Duration","_a","_b","SQSClient","DeleteMessageBatchCommand","ReceiveMessageCommand"],"mappings":"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"}
package/dist/index.cjs.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var AwsSqsConsumingEventPublisher = require('./cjs/AwsSqsConsumingEventPublisher-034938f3.cjs.js');
5
+ var AwsSqsConsumingEventPublisher = require('./cjs/AwsSqsConsumingEventPublisher-8341998e.cjs.js');
6
6
  require('@aws-sdk/client-sqs');
7
7
  require('luxon');
8
8
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import { LoggerService } from '@backstage/backend-plugin-api';
1
2
  import { PluginTaskScheduler } from '@backstage/backend-tasks';
2
3
  import { Config } from '@backstage/config';
3
- import { EventPublisher, EventBroker } from '@backstage/plugin-events-node';
4
- import { Logger } from 'winston';
4
+ import { EventsService } from '@backstage/plugin-events-node';
5
5
 
6
6
  /**
7
7
  * Publishes events received from an AWS SQS queue.
@@ -9,8 +9,9 @@ import { Logger } from 'winston';
9
9
  *
10
10
  * @public
11
11
  */
12
- declare class AwsSqsConsumingEventPublisher implements EventPublisher {
12
+ declare class AwsSqsConsumingEventPublisher {
13
13
  private readonly logger;
14
+ private readonly events;
14
15
  private readonly scheduler;
15
16
  private readonly topic;
16
17
  private readonly receiveParams;
@@ -18,15 +19,14 @@ declare class AwsSqsConsumingEventPublisher implements EventPublisher {
18
19
  private readonly queueUrl;
19
20
  private readonly taskTimeoutSeconds;
20
21
  private readonly waitTimeAfterEmptyReceiveMs;
21
- private eventBroker?;
22
22
  static fromConfig(env: {
23
23
  config: Config;
24
- logger: Logger;
24
+ events: EventsService;
25
+ logger: LoggerService;
25
26
  scheduler: PluginTaskScheduler;
26
27
  }): AwsSqsConsumingEventPublisher[];
27
28
  private constructor();
28
- setEventBroker(eventBroker: EventBroker): Promise<void>;
29
- private start;
29
+ start(): Promise<void>;
30
30
  private deleteMessages;
31
31
  private consumeMessages;
32
32
  private sleep;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-events-backend-module-aws-sqs",
3
- "version": "0.2.15",
3
+ "version": "0.3.0-next.0",
4
4
  "main": "./dist/index.cjs.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -40,21 +40,20 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@aws-sdk/client-sqs": "^3.350.0",
43
- "@backstage/backend-common": "^0.21.2",
44
- "@backstage/backend-plugin-api": "^0.6.12",
45
- "@backstage/backend-tasks": "^0.5.17",
46
- "@backstage/config": "^1.1.1",
47
- "@backstage/plugin-events-node": "^0.2.21",
43
+ "@backstage/backend-common": "^0.21.3-next.0",
44
+ "@backstage/backend-plugin-api": "^0.6.13-next.0",
45
+ "@backstage/backend-tasks": "^0.5.18-next.0",
46
+ "@backstage/config": "^1.1.2-next.0",
47
+ "@backstage/plugin-events-node": "^0.3.0-next.0",
48
48
  "@backstage/types": "^1.1.1",
49
- "luxon": "^3.0.0",
50
- "winston": "^3.2.1"
49
+ "luxon": "^3.0.0"
51
50
  },
52
51
  "devDependencies": {
53
52
  "@aws-sdk/types": "^3.347.0",
54
- "@backstage/backend-common": "^0.21.2",
55
- "@backstage/backend-test-utils": "^0.3.2",
56
- "@backstage/cli": "^0.25.2",
57
- "@backstage/plugin-events-backend-test-utils": "^0.1.22",
53
+ "@backstage/backend-common": "^0.21.3-next.0",
54
+ "@backstage/backend-test-utils": "^0.3.3-next.0",
55
+ "@backstage/cli": "^0.25.3-next.0",
56
+ "@backstage/plugin-events-backend-test-utils": "^0.1.23-next.0",
58
57
  "aws-sdk-client-mock": "^3.0.0"
59
58
  },
60
59
  "files": [
@@ -1 +0,0 @@
1
- {"version":3,"file":"AwsSqsConsumingEventPublisher-034938f3.cjs.js","sources":["../../src/publisher/config.ts","../../src/publisher/AwsSqsConsumingEventPublisher.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { HumanDuration, JsonObject } from '@backstage/types';\nimport { Duration } from 'luxon';\n\nconst CONFIG_PREFIX_MODULE = 'events.modules.awsSqs.';\nconst CONFIG_PREFIX_PUBLISHER = `${CONFIG_PREFIX_MODULE}awsSqsConsumingEventPublisher.`;\nconst DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE = { minutes: 1 };\nconst MAX_WAIT_SECONDS = 20;\n\nexport interface AwsSqsEventSourceConfig {\n pollingWaitTime: Duration;\n queueUrl: string;\n region: string;\n timeout: Duration;\n topic: string;\n visibilityTimeout?: Duration;\n waitTimeAfterEmptyReceive: Duration;\n endpoint?: string;\n}\n\n// TODO(pjungermann): validation could be improved similar to `convertToHumanDuration` at @backstage/backend-tasks\nfunction readOptionalHumanDuration(\n config: Config,\n key: string,\n): HumanDuration | undefined {\n return config.getOptional<JsonObject>(key) as HumanDuration;\n}\n\nfunction readOptionalDuration(\n config: Config,\n key: string,\n): Duration | undefined {\n const duration = readOptionalHumanDuration(config, key);\n return duration ? Duration.fromObject(duration) : undefined;\n}\n\nexport function readConfig(config: Config): AwsSqsEventSourceConfig[] {\n const key = `${CONFIG_PREFIX_PUBLISHER}topics`;\n const topics = config.getOptionalConfig(key);\n\n return (\n topics?.keys()?.map(topic => {\n const topicConfig = topics.getConfig(topic);\n const keyPrefix = `${key}.${topic}.`;\n\n // queue config:\n const pollingWaitTime = Duration.fromObject(\n readOptionalHumanDuration(topicConfig, 'queue.waitTime') ?? {\n seconds: MAX_WAIT_SECONDS,\n },\n );\n if (\n pollingWaitTime.valueOf() < 0 ||\n pollingWaitTime.as('seconds') > MAX_WAIT_SECONDS\n ) {\n throw new Error(\n `${keyPrefix}queue.waitTime must be within 0..${MAX_WAIT_SECONDS} seconds.`,\n );\n }\n const queueUrl = topicConfig.getString('queue.url');\n const region = topicConfig.getString('queue.region');\n const endpoint = topicConfig.getOptionalString('queue.endpoint');\n const visibilityTimeout = readOptionalDuration(\n topicConfig,\n 'queue.visibilityTimeout',\n );\n\n // task:\n const waitTimeAfterEmptyReceive = Duration.fromObject(\n readOptionalHumanDuration(topicConfig, 'waitTimeAfterEmptyReceive') ??\n DEFAULT_WAIT_TIME_AFTER_EMPTY_RECEIVE,\n );\n if (waitTimeAfterEmptyReceive.valueOf() < 0) {\n throw new Error(\n `The ${keyPrefix}waitTimeAfterEmptyReceive must not be negative.`,\n );\n }\n const timeout =\n readOptionalDuration(topicConfig, 'timeout') ??\n pollingWaitTime\n .plus(waitTimeAfterEmptyReceive)\n .plus(Duration.fromObject({ seconds: 180 }));\n if (\n timeout.valueOf() <=\n pollingWaitTime.valueOf() + waitTimeAfterEmptyReceive.valueOf()\n ) {\n throw new Error(\n `The ${keyPrefix}timeout must be greater than ${keyPrefix}queue.waitTime + ${keyPrefix}waitTimeAfterEmptyReceive.`,\n );\n }\n\n return {\n pollingWaitTime,\n queueUrl,\n endpoint,\n region,\n timeout,\n topic,\n visibilityTimeout,\n waitTimeAfterEmptyReceive,\n };\n }) ?? []\n );\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DeleteMessageBatchCommand,\n Message,\n ReceiveMessageCommand,\n ReceiveMessageCommandInput,\n SQSClient,\n} from '@aws-sdk/client-sqs';\nimport { PluginTaskScheduler } from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\nimport { EventBroker, EventPublisher } from '@backstage/plugin-events-node';\nimport { Logger } from 'winston';\nimport { AwsSqsEventSourceConfig, readConfig } from './config';\n\n/**\n * Publishes events received from an AWS SQS queue.\n * The message payload will be used as event payload and passed to registered subscribers.\n *\n * @public\n */\n// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.)\nexport class AwsSqsConsumingEventPublisher implements EventPublisher {\n private readonly topic: string;\n private readonly receiveParams: ReceiveMessageCommandInput;\n private readonly sqs: SQSClient;\n private readonly queueUrl: string;\n private readonly taskTimeoutSeconds: number;\n private readonly waitTimeAfterEmptyReceiveMs;\n private eventBroker?: EventBroker;\n\n static fromConfig(env: {\n config: Config;\n logger: Logger;\n scheduler: PluginTaskScheduler;\n }): AwsSqsConsumingEventPublisher[] {\n return readConfig(env.config).map(\n config =>\n new AwsSqsConsumingEventPublisher(env.logger, env.scheduler, config),\n );\n }\n\n private constructor(\n private readonly logger: Logger,\n private readonly scheduler: PluginTaskScheduler,\n config: AwsSqsEventSourceConfig,\n ) {\n this.topic = config.topic;\n\n this.receiveParams = {\n MaxNumberOfMessages: 10,\n MessageAttributeNames: ['All'],\n QueueUrl: config.queueUrl,\n VisibilityTimeout: config.visibilityTimeout?.as('seconds'),\n WaitTimeSeconds: config.pollingWaitTime.as('seconds'),\n };\n\n this.sqs = new SQSClient({\n region: config.region,\n endpoint: config.endpoint,\n });\n this.queueUrl = config.queueUrl;\n\n this.taskTimeoutSeconds = config.timeout.as('seconds');\n this.waitTimeAfterEmptyReceiveMs =\n config.waitTimeAfterEmptyReceive.as('milliseconds');\n }\n\n async setEventBroker(eventBroker: EventBroker): Promise<void> {\n this.eventBroker = eventBroker;\n return this.start();\n }\n\n private async start(): Promise<void> {\n const id = `events.awsSqs.publisher:${this.topic}`;\n const logger = this.logger.child({\n class: AwsSqsConsumingEventPublisher.prototype.constructor.name,\n taskId: id,\n });\n\n await this.scheduler.scheduleTask({\n id: id,\n frequency: { seconds: 0 },\n timeout: { seconds: this.taskTimeoutSeconds },\n scope: 'local',\n fn: async () => {\n try {\n const numMessages = await this.consumeMessages();\n if (numMessages === 0) {\n await this.sleep(this.waitTimeAfterEmptyReceiveMs);\n }\n } catch (error) {\n logger.error('Failed to consume AWS SQS messages', error);\n }\n },\n });\n }\n\n private async deleteMessages(messages?: Message[]): Promise<void> {\n if (!messages || messages.length === 0) {\n return;\n }\n\n const deleteParams = {\n QueueUrl: this.queueUrl,\n Entries: messages.map((message, index) => {\n return {\n Id: message.MessageId ?? `message-${index}`,\n ReceiptHandle: message.ReceiptHandle,\n };\n }),\n };\n\n try {\n const result = await this.sqs.send(\n new DeleteMessageBatchCommand(deleteParams),\n );\n if (result.Failed && result.Failed.length > 0) {\n this.logger.error(\n `Failed to delete ${result.Failed!.length} of ${\n messages.length\n } messages from AWS SQS ${this.queueUrl}. First: ${\n result.Failed[0].Message\n }`,\n );\n }\n } catch (error) {\n this.logger.error(\n `Failed to delete message from AWS SQS ${this.queueUrl}`,\n error,\n );\n }\n }\n\n private async consumeMessages(): Promise<number> {\n try {\n const data = await this.sqs.send(\n new ReceiveMessageCommand(this.receiveParams),\n );\n\n data.Messages?.forEach(message => {\n const eventPayload = JSON.parse(message.Body!);\n\n const metadata: Record<string, string | string[]> = {};\n Object.keys(message.MessageAttributes ?? {}).forEach(key => {\n const attrValue = message.MessageAttributes![key];\n if (\n !attrValue ||\n !attrValue.DataType ||\n !['String', 'Number'].includes(attrValue.DataType)\n ) {\n return;\n }\n\n const value = attrValue.StringListValues ?? attrValue.StringValue;\n if (value !== undefined) {\n metadata[key] = value;\n }\n });\n\n this.eventBroker!.publish({\n topic: this.topic,\n eventPayload,\n metadata,\n });\n });\n await this.deleteMessages(data.Messages);\n return data.Messages?.length ?? 0;\n } catch (error) {\n this.logger.error(\n `Failed to receive events from AWS SQS ${this.queueUrl}`,\n error,\n );\n return 0;\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise<void>(resolve => setTimeout(resolve, ms));\n }\n}\n"],"names":["Duration","_a","_b","SQSClient","DeleteMessageBatchCommand","ReceiveMessageCommand"],"mappings":"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"}