Mailspring/packages/client-app/internal_packages/sync-health-checker/lib/sync-health-checker.es6

115 lines
3.6 KiB
Plaintext
Raw Normal View History

import {ipcRenderer} from 'electron'
import {IdentityStore, AccountStore, Actions, NylasAPI, NylasAPIRequest} from 'nylas-exports'
const CHECK_HEALTH_INTERVAL = 5 * 60 * 1000;
class SyncHealthChecker {
constructor() {
this._lastSyncActivity = null
this._interval = null
}
start() {
if (this._interval) {
console.warn('SyncHealthChecker has already been started')
} else {
this._interval = setInterval(this._checkSyncHealth, CHECK_HEALTH_INTERVAL)
}
}
stop() {
clearInterval(this._interval)
this._interval = null
}
// This is a separate function so the request can be manipulated in the specs
_buildRequest = () => {
return new NylasAPIRequest({
api: NylasAPI,
options: {
accountId: AccountStore.accounts()[0].id,
path: `/health`,
},
});
}
_checkSyncHealth = async () => {
try {
if (!IdentityStore.identity()) {
return
}
const request = this._buildRequest()
const response = await request.run()
this._lastSyncActivity = response
} catch (err) {
if (/ECONNREFUSED/i.test(err.toString())) {
this._onWorkerWindowUnavailable()
} else {
err.message = `Error checking sync health: ${err.message}`
NylasEnv.reportError(err)
}
}
}
_onWorkerWindowUnavailable() {
let extraData = {};
// Extract data that we want to report. We'll report the entire
// _lastSyncActivity object, but it'll probably be useful if we can segment
// by the data in the oldest or newest entry, so we report those as
// individual values too.
const lastActivityEntries = Object.entries(this._lastSyncActivity || {})
if (lastActivityEntries.length > 0) {
const times = lastActivityEntries.map((entry) => entry[1].time)
const now = Date.now()
const maxTime = Math.max(...times)
const mostRecentEntry = lastActivityEntries.find((entry) => entry[1].time === maxTime)
const [mostRecentActivityAccountId, {
activity: mostRecentActivity,
time: mostRecentActivityTime,
}] = mostRecentEntry;
const mostRecentDuration = now - mostRecentActivityTime
const minTime = Math.min(...times)
const leastRecentEntry = lastActivityEntries.find((entry) => entry[1].time === minTime)
const [leastRecentActivityAccountId, {
activity: leastRecentActivity,
time: leastRecentActivityTime,
}] = leastRecentEntry;
const leastRecentDuration = now - leastRecentActivityTime
extraData = {
mostRecentActivity,
mostRecentActivityTime,
mostRecentActivityAccountId,
mostRecentDuration,
leastRecentActivity,
leastRecentActivityTime,
leastRecentActivityAccountId,
leastRecentDuration,
}
}
NylasEnv.reportError(new Error('Worker window was unavailable'), {
// This information isn't as useful in Sentry, but include it here until
// the data is actually sent to Mixpanel. (See the TODO below)
lastActivityPerAccount: this._lastSyncActivity,
...extraData,
})
// TODO: This doesn't make it to Mixpanel because our analytics process
// lives in the worker window. We should move analytics to the main process.
// https://phab.nylas.com/T8029
Actions.recordUserEvent('Worker Window Unavailable', {
lastActivityPerAccount: this._lastSyncActivity,
...extraData,
})
console.log(`Detected worker window was unavailable. Restarting it.`, this._lastSyncActivity)
ipcRenderer.send('ensure-worker-window')
}
}
export default new SyncHealthChecker()