diff --git a/packages/delivery-expo/delivery.js b/packages/delivery-expo/delivery.js index 2b87879e..a888b88d 100644 --- a/packages/delivery-expo/delivery.js +++ b/packages/delivery-expo/delivery.js @@ -61,7 +61,14 @@ module.exports = (client, fetch = global.fetch) => { } client._logger.info(`Sending event ${event.events[0].errors[0].errorClass}: ${event.events[0].errors[0].errorMessage}`) send(url, opts, err => { - if (err) return onerror(err, { url, opts }, 'event', cb) + if (err) { + // do not retry oversized payloads regardless of status code + if (body.length > 10e5) { + client._logger.warn(`Discarding over-sized event (${body.length / 10e5} MB) after failed delivery`) + err.isRetryable = false + } + return onerror(err, { url, opts }, 'event', cb) + } cb(null) }) } catch (e) { diff --git a/packages/delivery-expo/test/delivery.test.js b/packages/delivery-expo/test/delivery.test.js index a3c15e66..b13ec94f 100644 --- a/packages/delivery-expo/test/delivery.test.js +++ b/packages/delivery-expo/test/delivery.test.js @@ -202,6 +202,43 @@ describe('delivery: expo', () => { }) }) + it('does not attempt to re-send oversized payloads', done => { + // A 401 is considered retryable but this will be overridden by the payload size check + const { requests, server } = mockServer(401) + server.listen(err => { + expect(err).toBeUndefined() + + const lotsOfEvents = [] + while (JSON.stringify(lotsOfEvents).length < 10e5) { + lotsOfEvents.push({ errors: [{ errorClass: 'Error', errorMessage: 'long repetitive string'.repeat(1000) }] }) + } + const payload = { + events: lotsOfEvents + } + + const config = { + apiKey: 'aaaaaaaa', + endpoints: { notify: `http://0.0.0.0:${server.address().port}/notify/` }, + redactedKeys: [] + } + + const logger = { + info: jest.fn(), + warn: jest.fn(), + error: jest.fn() + } + + delivery({ _config: config, _logger: logger }, fetch).sendEvent(payload, (err) => { + expect(logger.warn).toHaveBeenCalledWith('Discarding over-sized event (1.014603 MB) after failed delivery') + expect(enqueueSpy).not.toHaveBeenCalled() + expect(err).toBeTruthy() + expect(requests.length).toBe(0) + server.close() + done() + }) + }) + }) + it('handles errors gracefully for sessions (ECONNREFUSED)', done => { const payload = { events: [{ errors: [{ errorClass: 'Error', errorMessage: 'foo is not a function' }] }]