function heartbeat() {
        heartbeatHandle = null;
        var currentInstance = mySyncNode.node && mySyncNode.node.id;
        if (!currentInstance) return;
        db.transaction('rw!', db._syncNodes, ()=>{
            db._syncNodes.where({id: currentInstance}).first(ourSyncNode => {
                if (!ourSyncNode) {
                    // We do not exist anymore. Call db.close() to teardown polls etc.
                    if (db.isOpen()) db.close();
                    return;
                }
                ourSyncNode.lastHeartBeat = Date.now();
                ourSyncNode.deleteTimeStamp = null; // Reset "deleteTimeStamp" flag if it was there.
                return db._syncNodes.put(ourSyncNode);
            });
        }).catch('DatabaseClosedError', () => {
            // Ignore silently
        }).finally(() => {
            if (mySyncNode.node && mySyncNode.node.id === currentInstance && db.isOpen()) {
                heartbeatHandle = setTimeout(heartbeat, HEARTBEAT_INTERVAL);
            }
        });
    }
The reason we need heartbeat in parallell with poll() is due to the risk of long-running
transactions while syncing changes from server to client in Dexie.Syncable. That transaction will
include _changes (which will block readChanges()) but not _syncNodes. So this heartbeat will go on
during that changes are being applied and update our lastHeartBeat property while poll() is waiting.
When cleanup() (who also is blocked by the sync) wakes up, it won't kill the master node because this
heartbeat job will have updated the master node's heartbeat during the long-running sync transaction.

If we did not have this heartbeat, and a server send lots of changes that took more than NODE_TIMEOUT
(20 seconds), another node waking up after the sync would kill the master node and take over because
it would believe it was dead.