Last modified: 2014-10-29 10:48:39 UTC
Use HTML5 storage as an intermediary queue so if an image doesn't successfully fire, we have a chance to pull the log entry out of storage and try again. Duplicate firings are a possibility (the browser could fire without us getting confirmation), so we will probably have to generate a unique ID and de-duplicate on the server.
The localStorage API is synchronous, so it's possible to reliably set an item in localStorage in an on click handler without having to resort to voodoo. (According to http://www.nczonline.net/blog/2012/03/07/in-defense-of-localstorage/, IE 8's implementation is asynchronous. But I'm sure we could hack around it somehow.) There are serious questions to answer, though: * What if the link navigates away from Wikipedia entirely? You might simply assume that the user will come back eventually, and you'll fire the event then. But then the server timestamp is no longer an accurate indicator of when an event took place. We'd have to reintroduce client-side timestamps, I think. * Does it make sense to implement this in ext.eventLogging.core.js? We could rewrite mw.eventLog.logEvent to write to localStorage by default, and poll it asynchronously using setInterval to actually log events to the server. Ideas?
If we had CORS, we could use $.ajax( { asynchronous: false, ... } ).
Batching events will make us much more reliant on client-side timestamps and thus open up a can of worms. A robust alternative to $.fn.stall is needed, but localStorage is just one possible approach. I'm going to create a separate bug for $.fn.stall and close this as WONTFIX for now.
(In reply to comment #3) > I'm going to create a separate bug for $.fn.stall and > close this as WONTFIX for now. Ugh, I changed my mind about this but submitted the comment by accident when I changed the title. This should be the bug for tracking synchronous event logging.
I confirmed that $.ajax({ async: false }) requests work. You only need CORS if you want to handle the response, which we don't care about: we only care that the request is made against bits, which it is.
I don't think we really want synchronous network requests. They block the entire event loop and can cause other problems (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FSynchronous_and_Asynchronous_Requests). I think we can distinguish between persistent logging and synchronous logging. 'Persistent' means it will try again until it's logged successfully (or it reaches a maximum number of attempts). 'Synchronous' means it logs, blocking the event loop, immediately when logEvent is called.
The Beacon API proposal from the W3C Web Performance Working Group, published last month, takes a stab at solving the exact problem that this bug describes: https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/Beacon/Overview.html The proposal itself is just that -- a proposal. I don't think any browser vendors implement it yet. But it's highly useful, because it tells us that this is indeed a thorny problem, not just something we haven't figured out, and because it gives a concise overview of existing techniques & their limitations. This part of the proposal is worth quoting in full: "User agents will typically ignore asynchronous XMLHttpRequests made in an unload handler. To solve this problem, analytics and diagnostics code will typically make a synchronous XMLHttpRequest in an unload or beforeunload handler to submit the data. The synchronous XMLHttpRequest forces the user agent to delay unloading the document, and makes the next navigation appear to be slower. There is little the next page can do to avoid this perception of poor page load performance. "In addition, there are other poor patterns used to ensure that data is submitted. One such pattern to delay the unload in order to submit data is to create an Image element and set its src attribute within the unload handler. As most user agents will delay the unload to complete the pending image load, data can be submitted during the unload. Another technique is to create a no-op loop for several seconds within the unload handler to delay the unload and submit data to a server. "Not only do these techniques represent poor coding patterns, some of them are unreliable and also result in the perception of poor page load performance for the next navigation."
[moving from MediaWiki extensions to Analytics product - see bug 61946]
Bumping the priority on this and renaming somewhat, since this seems to be the preferred approach (for performance reasons) for moving forward on the link click problem. See discussion at https://bugzilla.wikimedia.org/show_bug.cgi?id=52287 . I propose using jQuery jStorage, which is a localStorage wrapper (already in core) with support for globalStorage and IE userData as a fallback.
(In reply to Matthew Flaschen from comment #9) > I propose using jQuery jStorage, which is a localStorage wrapper (already in > core) with support for globalStorage and IE userData as a fallback. To be clearer, jStorage has support for globalStorage and userData too. We wouldn't need to add that.
(In reply to Ori Livneh from comment #7) > The Beacon API proposal from the W3C Web Performance Working Group, > published last month, takes a stab at solving the exact problem that this > bug describes: > https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/Beacon/Overview.html > > The proposal itself is just that -- a proposal. I don't think any browser > vendors implement it yet. Firefox landed it recently in stable: https://developer.mozilla.org/en-US/docs/Web/API/navigator.sendBeacon https://developer.mozilla.org/en-US/Firefox/Releases/31 Chrome landed it in canary (Chrome 37), soon to be in stable: https://code.google.com/p/chromium/issues/detail?id=360603
(In reply to Krinkle from comment #11) > Firefox landed it recently in stable: > https://developer.mozilla.org/en-US/docs/Web/API/navigator.sendBeacon > https://developer.mozilla.org/en-US/Firefox/Releases/31 > > Chrome landed it in canary (Chrome 37), soon to be in stable: > https://code.google.com/p/chromium/issues/detail?id=360603 This seems like a good choice then. We can use sendBeacon when available, and use jStorage when it's not. However, ideally, the issue with localStorage being used up should be solved first, or the fallback will be less effective (or have to use cookies).
Change 162194 had a related patch set uploaded by Prtksxna: Add an experimental function to log events using the sendBeacon API. https://gerrit.wikimedia.org/r/162194