-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Offline storage plugin #1165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Offline storage plugin #1165
Conversation
Stores errors failed to get send and try to send them when Network comes back or on init
plugins/offline-storage.js
Outdated
|
||
var offlineStorageKey = 'raven-js-offline-queue'; | ||
|
||
function offlineStoragelugin(Raven, options) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type in offlineStoragelugin
plugins/offline-storage.js
Outdated
window.addEventListener(options.onlineEventName || 'online', processOfflineQueue); | ||
} | ||
|
||
module.exports = offlineStoragelugin; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo here as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks
plugins/offline-storage.js
Outdated
var queue = JSON.parse(localStorage.getItem(offlineStorageKey)) || []; | ||
|
||
// Store an empty queue. If processing these one fails they get back to the queue | ||
localStorage.setItem(offlineStorageKey, JSON.stringify([])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can call removeItem
instead to be more direct. It'll fallback to []
anyway during processing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true :)
queue.forEach(function processOfflinePayload(data) { | ||
// Avoid duplication verification for offline stored | ||
// as they may try multiple times to be processed | ||
Raven._lastData = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I understand your comment here.
There shouldn't be any duplicates here already, as failure
event is triggered at the end of _sendProcessedPayload
which already checks for duplicates first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but then when trying to send it again when get back offline, because _lastData
is set with potentially the same data we will be try to send, it will be missed because it's the same data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right :)
plugins/offline-storage.js
Outdated
|
||
try { | ||
var queue = JSON.parse(localStorage.getItem(offlineStorageKey)) || []; | ||
queue.push(event.data || Raven._lastData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of falling back to _lastData
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure, from what I have seen they will have(and be) to be the same right?
I can remove the fallback.
}); | ||
|
||
// Add event listener on online or custom event to trigger offline queue sending | ||
window.addEventListener(options.onlineEventName || 'online', processOfflineQueue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any alternative event that I don't know of, but could be used here? :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just because the application might rely on a different event for letting other plugins know when the connection is available (e.g. on our cordova-based hybrid app we trigger a "foo-bar-online" event to the document when we're sure the app is online and it was able to make an XHR request), because "online" can easily mean "connected to the network" as in "local network" but still not be connected to the internet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes perfect sense
Based on PR review
@kamilogorek Thank you som much for your review! |
I'd say the implementation is fine now, thanks! :) |
Great, thanks. |
No rush, take your time :) |
var queue = JSON.parse(localStorage.getItem(offlineStorageKey)) || []; | ||
|
||
// Store an empty queue. If processing these one fails they get back to the queue | ||
localStorage.removeItem(offlineStorageKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
multiple localStorage operations are not atomic. It is possible for multiple tabs to receive this queue before the removeItem
. This needs to be inside a lock. See more info here:
https://medium.engineering/wait-dont-touch-that-a211832adc3a
http://balpha.de/2012/03/javascript-concurrency-and-locking-the-html5-localstorage/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@graingert I don't believe that library handles atomic operations between multiple browser windows. It just removes oldest item when localstorage when it's full
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is a link to a library I created to solve this problem. There are probably other libraries out there as well. Also feel free to just copy the library code into this repo if you don't want another dependency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Storing an entire array of the logs at once can be quite a poor usage of memory. There might be a lot of logs if a device is left offline for extended periods of time. On hybrid apps there is a very small memory limit. If there are a lot of logs or large json encoded objects, memory can spike. Possibly using indexdb or an option for a custom storage adapter would allow for more memory efficient ways of storing.
* Offline Storage plugin | ||
* | ||
* Stores errors failed to get send and try to send them when | ||
* Networkf comes back or on init |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(sorry, this is a drive-by comment)
is this a typo, Networkf
? should be Network
, right?
/** | ||
* Offline Storage plugin | ||
* | ||
* Stores errors failed to get send and try to send them when |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should failed to get send
be that failed to be sent
?
Not relevant for sentry-javascript SDK v4. |
@kamilogorek I am excited to hear that apparently raven will support offline natively. Any estimate on when we can expect to see v4? |
@AgDude Sentry core and node packages are already released as beta. We also merged major browser sdk rewrite (https://github.com/getsentry/sentry-javascript/commits/master quite a lot of commits :p) Today and now in a process of cleaning things outs. v4 will be extensible in a lot of ways, therefore adding offline integration (we'll write it ourselves anyway) will be a breeze :) It should be released as a major version early Q3, around September/October. |
Sounds great! Thanks for the update. |
Awesome! Thanks |
@kamilogorek We too are interested in capturing errors offline. Any update on this? If someone can provide general direction on the recommended approach I have time to work on this... or test a work in progress. I see from your August 2nd comment that it appears this can be built as an Sentry 4 "Integration"? |
@joelryan2k veeeery rough sketch of what it can look like. We'll definitely release an official integration, but we still have a lot of things to polish first. import { configureScope, captureEvent } from '@sentry/browser';
import { serialize, deserialize } from '@sentry/utils/object';
class Offline {
constructor() {
// initialize storage
this.storage = someApi;
// get items
this.queue = this.storage.getEvents();
// drain them
this.drainQueue(this.queue);
}
install() {
configureScope(scope => scope.addEventProcessor(async (event) => {
if (isOnline()) {
return event;
}
await this.storeEvent(event);
return event;
}))
}
storeEvent(event) {
return this.storage.storeEvent(serialize(event));
}
drainQueue(queue) {
// send each one to sentry
queue.forEach((event) => captureEvent(deserialize(event)));
}
} |
Created #1633 to keep a track of this feature |
This is my proposal to #279. Any thoughts/suggestions to improve or make it different are welcome.
Thanks.
(#973 continues here.)
Description
Stores errors failed to get send and try to send them when network comes back or on init
Options
online
you can pass it here.TODO
If this works for you I'm missing documentation and tests.