Skip to content

Commit dca7620

Browse files
authored
feat: Throw by default from failed SQS publish (#1194)
Currently, sending an SQS message using `SQSService` does not throw an error by default. This has caught us out a couple of times where we were expecting a failure. The `failureMode` parameter was added to opt in to throwing errors, to avoid introducing a breaking change in v1. In v2 we'll throw errors by default, and you'll have to opt _out_ of this behaviour. BREAKING CHANGE: `SQSService#publish` throws by default instead of handling errors. To maintain old behaviour, you can pass `"catch"` in the `failureMode` parameter.
1 parent 7bac68d commit dca7620

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

docs/migration/v2.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This doc summarises the breaking changes introduced in v2 and what you need to d
77
- [Dependency injection](#dependency-injection)
88
- [Services](#services)
99
- [RequestService](#requestservice)
10+
- [SQSService](#sqsservice)
1011
- [Models](#models)
1112
- [StatusModel](#statusmodel)
1213
- [SQSMessageModel](#sqsmessagemodel)
@@ -161,6 +162,17 @@ There are some small breaking changes to the built-in services. We've tried to m
161162

162163
Header names returned by `getAllHeaders` are now lowercased. This is consistent with many other libraries (e.g. `http`, `axios`) and makes it easier to work with HTTP headers. In some cases it may be easier to change existing code to use `getHeader`, which has provided case-insensitive access to headers since [v1.2.0](https://github.com/comicrelief/lambda-wrapper/releases/tag/v1.2.0).
163164

165+
### `SQSService`
166+
167+
In v1, the default behaviour of `publish` was to catch any error thrown while sending the message to SQS. In v2, this has been changed and it will now throw an error by default. In most scenarios this is the more intuitive mode, as it ensures that the caller is made aware of any SQS-related failure. To maintain the old behaviour, you can pass `"catch"` in the `failureMode` parameter.
168+
169+
```js
170+
// v1
171+
sqs.publish(queue, message);
172+
// v2 equivalent
173+
sqs.publish(queue, message, null, 'catch');
174+
```
175+
164176
## Models
165177

166178
The `Model` base class has been removed. It's hard to make it type-safe (it tries to dynamically call setter methods) and we do modelling and validation differently now, using our [data-models](https://github.com/comicrelief/data-models) repo which is based around [Yup](https://github.com/jquense/yup).

src/services/SQSService.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,10 +429,11 @@ export default class SQSService<
429429
* @param messageObject object
430430
* @param messageGroupId string
431431
* @param failureMode Choose how failures are handled:
432-
* - `catch`: errors will be caught and logged. This is the default.
433-
* - `throw`: errors will be thrown, causing promise to reject.
432+
* - `throw`: errors will be thrown, causing promise to reject. (default)
433+
* - `catch`: errors will be caught and logged. Useful for non-critical
434+
* messages.
434435
*/
435-
async publish(queue: QueueName<TConfig>, messageObject: object, messageGroupId = null, failureMode: 'catch' | 'throw' = SQS_PUBLISH_FAILURE_MODES.CATCH) {
436+
async publish(queue: QueueName<TConfig>, messageObject: object, messageGroupId = null, failureMode: 'catch' | 'throw' = SQS_PUBLISH_FAILURE_MODES.THROW) {
436437
if (!Object.values(SQS_PUBLISH_FAILURE_MODES).includes(failureMode)) {
437438
throw new Error(`Invalid value for 'failureMode': ${failureMode}`);
438439
}

tests/unit/services/SQSService.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,22 +318,22 @@ describe('unit.services.SQSService', () => {
318318
});
319319

320320
describe('failure modes', () => {
321-
it(`catches the error if publish fails with failureMode === ${SQS_PUBLISH_FAILURE_MODES.CATCH}`, async () => {
321+
it('throws the error if publish fails with failureMode omitted', async () => {
322322
const service = getService({
323323
sendMessage: new Error('SQS is down!'),
324324
}, false);
325325

326-
const promise = service.publish(TEST_QUEUE, { test: 1 }, null, SQS_PUBLISH_FAILURE_MODES.CATCH);
326+
const promise = service.publish(TEST_QUEUE, { test: 1 }, null);
327327

328-
await expect(promise).resolves.toEqual(null);
328+
await expect(promise).rejects.toThrowError('SQS is down!');
329329
});
330330

331-
it('catches the error if publish fails with failureMode omitted', async () => {
331+
it(`catches the error if publish fails with failureMode === ${SQS_PUBLISH_FAILURE_MODES.CATCH}`, async () => {
332332
const service = getService({
333333
sendMessage: new Error('SQS is down!'),
334334
}, false);
335335

336-
const promise = service.publish(TEST_QUEUE, { test: 1 }, null);
336+
const promise = service.publish(TEST_QUEUE, { test: 1 }, null, SQS_PUBLISH_FAILURE_MODES.CATCH);
337337

338338
await expect(promise).resolves.toEqual(null);
339339
});

0 commit comments

Comments
 (0)