diff --git a/workers/sender/src/index.ts b/workers/sender/src/index.ts index 242d2da8..a52b05c5 100644 --- a/workers/sender/src/index.ts +++ b/workers/sender/src/index.ts @@ -192,7 +192,7 @@ export default abstract class SenderWorker extends Worker { this.logger.info(`Sending ${notificationType} notification to ${channel.endpoint}`); - this.provider.send(channel.endpoint, { + await this.provider.send(channel.endpoint, { type: notificationType, payload: { host: process.env.GARAGE_URL, @@ -245,7 +245,7 @@ export default abstract class SenderWorker extends Worker { return; } - this.provider.send(endpoint, { + await this.provider.send(endpoint, { type: 'assignee', payload: { host: process.env.GARAGE_URL, @@ -506,7 +506,7 @@ export default abstract class SenderWorker extends Worker { return; } - this.provider.send(endpoint, { + await this.provider.send(endpoint, { type: 'payment-failed', payload: { host: process.env.GARAGE_URL, @@ -541,7 +541,7 @@ export default abstract class SenderWorker extends Worker { return; } - this.provider.send(endpoint, { + await this.provider.send(endpoint, { type: 'payment-success', payload: { host: process.env.GARAGE_URL, @@ -560,7 +560,7 @@ export default abstract class SenderWorker extends Worker { private async handlePasswordResetTask(task: SenderWorkerPasswordResetTask): Promise { const { newPassword, endpoint } = task.payload; - this.provider.send(endpoint, { + await this.provider.send(endpoint, { type: 'password-reset', payload: { host: process.env.GARAGE_URL, @@ -578,7 +578,7 @@ export default abstract class SenderWorker extends Worker { private async handleWorkspaceInviteTask(task: SenderWorkerWorkspaceInviteTask): Promise { const { workspaceName, inviteLink, endpoint } = task.payload; - this.provider.send(endpoint, { + await this.provider.send(endpoint, { type: 'workspace-invite', payload: { host: process.env.GARAGE_URL, @@ -597,7 +597,7 @@ export default abstract class SenderWorker extends Worker { private async handleSignUpTask(task: SenderWorkerSignUpTask): Promise { const { password, endpoint } = task.payload; - this.provider.send(endpoint, { + await this.provider.send(endpoint, { type: 'sign-up', payload: { host: process.env.GARAGE_URL, diff --git a/workers/sender/tests/worker.test.ts b/workers/sender/tests/worker.test.ts index 73a9b5ae..ef5b0512 100644 --- a/workers/sender/tests/worker.test.ts +++ b/workers/sender/tests/worker.test.ts @@ -249,4 +249,33 @@ describe('Sender Worker', () => { expect(dailyEventsQueryMock).toBeCalledWith({ groupHash: 'groupHash' }); }); }); + + describe('provider.send awaiting', () => { + /** + * Without await, handle() resolves even if send() rejects — + * message would be acked and the error lost. + * The .catch on the rejected promise only prevents an unhandledRejection + * crash in the fire-and-forget case; await still observes the rejection. + */ + it('should reject handle when provider.send fails', async () => { + const worker = new ExampleSenderWorker(); + const sendError = new Error('provider send failed'); + + (worker as any).provider.send = jest.fn(() => { + const sendPromise = Promise.reject(sendError); + + sendPromise.catch(() => undefined); + + return sendPromise; + }); + + await expect(worker.handle({ + type: 'sign-up', + payload: { + password: 'secret', + endpoint: 'user@example.com', + }, + })).rejects.toThrow('provider send failed'); + }); + }); });