Detecting Browser/Tab crashes
This POC shows how browser crashes could potentially be detected.
How to run the demo?
- Run
npm run dev
- Run
npm run server
- Open http://localhost:1234
You can open multiple tabs (each tab will get a unique name)
- Logs are sent to the terminal via server.js
- Try various actions that can simulate a crash
- Once a crash is detected it will be sent to the server and stored in local memory
- http://localhost:1234 will show crashes that were reported
Resources
- https://github.com/getsentry/sentry-javascript/issues/5280
- http://jasonjl.me/blog/2015/06/21/taking-action-on-browser-crashes/
- https://medium.com/@JackPu/how-to-check-browser-crash-via-javascript-fa7d5af5e80b
How does it work?
There are two basic concepts:
- Tab tracking
Each browser tab reports its current state on regular intervals. The current state is saved in IndexedDB as a state report.
The state report contains properties like: last time when it was active, url, memory usage, etc.
The state report is removed from the database when then the tab is closed by the user.
- Crash detection
A separate process reads all currently stored state reports. If it happens that there's a stale state report that is still in the database but updated for long period of time it means the tab was not closed correctly or stopped responding and it probably crashed.
How to use it in a project?
You need to create 2 files for workers and run init function in your app:
detector.worker.js
import { initDetectorWorker } from 'crashme';
initDetectorWorker({
dbName: 'crashme.crashes',
crashThreshold: 5000,
interval: 5000,
});
client.worker.js
import { initDetectorWorker } from 'crashme';
initClientWorker({
dbName: 'crashme.crashes',
pingInterval: 1000,
});
and run function to initialize detection:
import { initCrashDetection } from 'crashme';
export function startReportingCrashes() {
initCrashDetection({
id: Math.random().toString(36).substr(2,5),
dbName: 'crashme.crashes',
createClientWorker: () => {
return new Worker(new URL('./client.worker', import.meta.url));
},
createDetectorWorker: () => {
return new SharedWorker(new URL('./detector.worker', import.meta.url));
},
reportCrash: async (tab) => {
return true;
},
updateInfo: (report) => {
},
});
}
More info why 2 separate workers are needed is described here.