Skip to content

Commit 734e5c6

Browse files
committed
If Sentry responds with 413 request too large, try to send the exception again without any state
1 parent 0ab4e52 commit 734e5c6

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

.eslintrc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
],
1010
"rules": {
1111
"prettier/prettier": "error",
12-
"prefer-arrow-callback": "error"
12+
"prefer-arrow-callback": "error",
13+
"prefer-reflect": "off",
1314
},
1415
"parserOptions": {
1516
"ecmaVersion": 8,
@@ -20,4 +21,4 @@
2021
"node": true,
2122
"es6": true
2223
}
23-
}
24+
}

index.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,50 @@ function createRavenMiddleware(Raven, options = {}) {
3232
return original ? original(data) : data;
3333
});
3434

35+
const retryCaptureWithoutReduxState = captureFn => {
36+
Raven.setDataCallback((data, originalCallback) => {
37+
Raven.setDataCallback(originalCallback);
38+
const reduxExtra = {
39+
lastAction: actionTransformer(lastAction),
40+
state: "Failed to submit state to Sentry: 413 request too large."
41+
};
42+
data.extra = Object.assign(reduxExtra, data.extra);
43+
data.breadcrumbs.values = [];
44+
return data;
45+
});
46+
// Raven has an internal check for duplicate errors that we need to disable.
47+
const originalAllowDuplicates = Raven._globalOptions.allowDuplicates;
48+
Raven._globalOptions.allowDuplicates = true;
49+
captureFn();
50+
Raven._globalOptions.allowDuplicates = originalAllowDuplicates;
51+
};
52+
53+
const retryWithoutStateOnRequestTooLarge = originalFn => {
54+
return (...captureArguments) => {
55+
const originalTransport = Raven._globalOptions.transport;
56+
Raven.setTransport(opts => {
57+
Raven.setTransport(originalTransport);
58+
opts.onError = error => {
59+
if (error.request && error.request.status === 413) {
60+
// Retry request without state after "413 request too large" error
61+
retryCaptureWithoutReduxState(() => {
62+
originalFn.apply(Raven, captureArguments);
63+
});
64+
}
65+
};
66+
(originalTransport || Raven._makeRequest).call(Raven, opts);
67+
});
68+
originalFn.apply(Raven, captureArguments);
69+
};
70+
};
71+
72+
Raven.captureException = retryWithoutStateOnRequestTooLarge(
73+
Raven.captureException
74+
);
75+
Raven.captureMessage = retryWithoutStateOnRequestTooLarge(
76+
Raven.captureMessage
77+
);
78+
3579
return next => action => {
3680
// Log the action taken to Raven so that we have narrative context in our
3781
// error report.

index.test.js

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ const Raven = require("raven-js");
22
const createRavenMiddleware = require("./index");
33
const { createStore, applyMiddleware } = require("redux");
44

5-
Raven.config("https://5d5bf17b1bed4afc9103b5a09634775e@sentry.io/146969", {
6-
allowDuplicates: true
7-
}).install();
5+
Raven.config(
6+
"https://5d5bf17b1bed4afc9103b5a09634775e@sentry.io/146969"
7+
).install();
88

99
const reducer = (previousState = { value: 0 }, action) => {
1010
switch (action.type) {
@@ -32,7 +32,7 @@ describe("raven-for-redux", () => {
3232
Raven.setDataCallback(undefined);
3333
Raven.setBreadcrumbCallback(undefined);
3434
Raven.setUserContext(undefined);
35-
35+
Raven._globalOptions.allowDuplicates = true;
3636
Raven._breadcrumbs = [];
3737
Raven._globalContext = {};
3838
});
@@ -186,6 +186,32 @@ describe("raven-for-redux", () => {
186186
userData
187187
);
188188
});
189+
190+
["captureException", "captureMessage"].forEach(fnName => {
191+
it(`retries ${fnName} without any state if Sentry returns 413 request too large`, () => {
192+
context.mockTransport.mockImplementationOnce(options => {
193+
options.onError({ request: { status: 413 } });
194+
});
195+
// allowDuplicates is set to true inside our handler and reset afterwards
196+
Raven._globalOptions.allowDuplicates = null;
197+
Raven[fnName].call(Raven, new Error("Crash!"));
198+
199+
// Ensure transport and allowDuplicates have been reset
200+
expect(Raven._globalOptions.transport).toEqual(context.mockTransport);
201+
expect(Raven._globalOptions.allowDuplicates).toEqual(null);
202+
expect(context.mockTransport).toHaveBeenCalledTimes(2);
203+
const { extra } = context.mockTransport.mock.calls[0][0].data;
204+
expect(extra).toMatchObject({
205+
state: { value: 0 },
206+
lastAction: undefined
207+
});
208+
const { extra: extra2 } = context.mockTransport.mock.calls[1][0].data;
209+
expect(extra2).toMatchObject({
210+
state: "Failed to submit state to Sentry: 413 request too large.",
211+
lastAction: undefined
212+
});
213+
});
214+
});
189215
});
190216
describe("with all the options enabled", () => {
191217
beforeEach(() => {

0 commit comments

Comments
 (0)