Skip to content
This repository was archived by the owner on Oct 31, 2024. It is now read-only.

Commit d48c31a

Browse files
authored
Merge pull request #3 from aspecto-io/fix/events
Fix/events
2 parents 73e1eb8 + 9b1d7a8 commit d48c31a

File tree

4 files changed

+114
-15
lines changed

4 files changed

+114
-15
lines changed

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ await sqsProducer.sendJSON({
7272
### SQS Consumer
7373

7474
```ts
75-
import { SqsConsumer } from 'sns-sqs-big-payload';
75+
import { SqsConsumer, SqsConsumerEvents } from 'sns-sqs-big-payload';
7676

7777
const sqsConsumer = SqsConsumer.create({
7878
queueUrl: '...',
@@ -95,6 +95,11 @@ const sqsConsumer = SqsConsumer.create({
9595
},
9696
});
9797

98+
// to subscribe for events
99+
sqsConsumer.on(SqsConsumerEvents.messageProcessed, () => {
100+
// ...
101+
});
102+
98103
sqsConsumer.start();
99104

100105
// to stop processing
@@ -140,7 +145,14 @@ consumer.start();
140145

141146
## Events and logging
142147

143-
SqsConsumer has an [EventEmitter](https://nodejs.org/api/events.html) and send the following events:
148+
SqsConsumer has an internal [EventEmitter](https://nodejs.org/api/events.html), you can subscribe for events like this:
149+
```ts
150+
sqsConsumer.on(SqsConsumerEvents.messageProcessed, () => {
151+
// ...
152+
});
153+
```
154+
155+
It sends the following events:
144156

145157
| Event | Params | Description |
146158
| ------------------- | ---------------- | ----------------------------------------------------------------------------------- |

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sns-sqs-big-payload",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"license": "MIT",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/sqs-consumer.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ export interface SqsConsumerOptions {
1919
transformMessageBody?(messageBody: any): any;
2020
}
2121

22-
enum SqsConsumerEvents {
22+
export enum SqsConsumerEvents {
2323
started = 'started',
2424
messageReceived = 'message-received',
25+
messageParsed = 'message-parsed',
2526
messageProcessed = 'message-processed',
2627
stopped = 'stopped',
2728
error = 'error',
@@ -96,6 +97,10 @@ export class SqsConsumer {
9697
this.events.emit(SqsConsumerEvents.stopped);
9798
}
9899

100+
on(event: string | symbol, handler: (...args: any) => void): void {
101+
this.events.on(event, handler);
102+
}
103+
99104
private poll(): void {
100105
if (!this.started) return;
101106
let currentPollingInterval = this.pollingInterval;
@@ -141,7 +146,10 @@ export class SqsConsumer {
141146
const messageBody = this.transformMessageBody ? this.transformMessageBody(message.Body) : message.Body;
142147
const rawPayload = await this.getMessagePayload(messageBody);
143148
const payload = this.parseMessagePayload(rawPayload);
144-
await this.handleMessage({ payload, message });
149+
this.events.emit(SqsConsumerEvents.messageParsed, { message, payload });
150+
if (this.handleMessage) {
151+
await this.handleMessage({ payload, message });
152+
}
145153
await this.deleteMessage(message);
146154
this.events.emit(SqsConsumerEvents.messageProcessed, message);
147155
} catch (err) {

tests/sns-sqs.spec.ts

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
SqsConsumerEvents,
23
SqsProducer,
34
SqsConsumer,
45
SqsProducerOptions,
@@ -93,28 +94,51 @@ async function publishMessage(msg: any, options: Partial<SnsProducerOptions> = {
9394
await snsProducer.publishJSON(msg);
9495
}
9596

96-
async function receiveMessages(expectedMsgsCount: number, options: Partial<SqsConsumerOptions> = {}): Promise<any> {
97+
async function receiveMessages(
98+
expectedMsgsCount: number,
99+
options: Partial<SqsConsumerOptions> = {},
100+
eventHandlers?: Record<string | symbol, (...args) => void>
101+
): Promise<any> {
97102
const { s3 } = getClients();
98-
return new Promise((res, rej) => {
103+
return new Promise((resolve, rej) => {
99104
const messages = [];
100105
let timeoutId;
101106

102107
const sqsConsumer = SqsConsumer.create({
103108
queueUrl: TEST_QUEUE_URL,
104109
region: TEST_REGION,
105110
parsePayload: (raw) => JSON.parse(raw),
106-
handleMessage: async ({ payload }) => {
107-
messages.push(payload);
108-
if (messages.length === expectedMsgsCount) {
109-
sqsConsumer.stop();
110-
clearTimeout(timeoutId);
111-
res(messages);
112-
}
113-
},
114111
...options,
115112
s3,
116113
});
117114

115+
sqsConsumer.on(SqsConsumerEvents.messageParsed, ({ payload }) => {
116+
messages.push(payload);
117+
});
118+
119+
sqsConsumer.on(SqsConsumerEvents.messageProcessed, () => {
120+
if (messages.length === expectedMsgsCount) {
121+
sqsConsumer.stop();
122+
clearTimeout(timeoutId);
123+
resolve(messages);
124+
}
125+
});
126+
127+
sqsConsumer.on(SqsConsumerEvents.error, () => {
128+
sqsConsumer.stop();
129+
clearTimeout(timeoutId);
130+
});
131+
132+
sqsConsumer.on(SqsConsumerEvents.processingError, () => {
133+
sqsConsumer.stop();
134+
clearTimeout(timeoutId);
135+
resolve();
136+
});
137+
138+
if (eventHandlers) {
139+
Object.entries(eventHandlers).forEach(([event, handler]) => sqsConsumer.on(event, handler));
140+
}
141+
118142
timeoutId = setTimeout(() => {
119143
rej(new Error("Timeout: SqsConsumer didn't get any messages for 5 seconds."));
120144
sqsConsumer.stop();
@@ -153,6 +177,61 @@ describe('sns-sqs-big-payload', () => {
153177
});
154178
});
155179

180+
describe('events', () => {
181+
function getEventHandlers() {
182+
const handlers = Object.keys(SqsConsumerEvents).reduce((acc, key) => {
183+
acc[SqsConsumerEvents[key]] = jest.fn();
184+
return acc;
185+
}, {});
186+
return handlers;
187+
}
188+
189+
it('should trigger success events event', async () => {
190+
const message = { it: 'works' };
191+
const handlers = getEventHandlers();
192+
sendMessage(message);
193+
const [receivedMessage] = await receiveMessages(1, {}, handlers);
194+
expect(receivedMessage).toEqual(message);
195+
196+
// success
197+
expect(handlers[SqsConsumerEvents.started]).toBeCalled();
198+
expect(handlers[SqsConsumerEvents.messageReceived]).toBeCalled();
199+
expect(handlers[SqsConsumerEvents.messageParsed]).toBeCalled();
200+
expect(handlers[SqsConsumerEvents.messageProcessed]).toBeCalled();
201+
expect(handlers[SqsConsumerEvents.stopped]).toBeCalled();
202+
// errors
203+
expect(handlers[SqsConsumerEvents.error]).not.toBeCalled();
204+
expect(handlers[SqsConsumerEvents.processingError]).not.toBeCalled();
205+
expect(handlers[SqsConsumerEvents.payloadParseError]).not.toBeCalled();
206+
expect(handlers[SqsConsumerEvents.s3PayloadError]).not.toBeCalled();
207+
expect(handlers[SqsConsumerEvents.connectionError]).not.toBeCalled();
208+
});
209+
210+
it('should should trigger processingError event', async () => {
211+
const message = { it: 'works' };
212+
const handlers = getEventHandlers();
213+
sendMessage(message);
214+
await receiveMessages(
215+
1,
216+
{
217+
handleMessage: () => {
218+
throw new Error('Processing error');
219+
},
220+
},
221+
handlers
222+
);
223+
224+
// errors
225+
expect(handlers[SqsConsumerEvents.messageReceived]).toBeCalled();
226+
expect(handlers[SqsConsumerEvents.messageParsed]).toBeCalled();
227+
expect(handlers[SqsConsumerEvents.processingError]).toBeCalled();
228+
expect(handlers[SqsConsumerEvents.messageProcessed]).not.toBeCalled();
229+
expect(handlers[SqsConsumerEvents.error]).not.toBeCalled();
230+
expect(handlers[SqsConsumerEvents.connectionError]).not.toBeCalled();
231+
expect(handlers[SqsConsumerEvents.payloadParseError]).not.toBeCalled();
232+
});
233+
});
234+
156235
describe('sending message through s3', () => {
157236
it('should send all message though s3 if configured', async () => {
158237
const message = { it: 'works' };

0 commit comments

Comments
 (0)