mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 01:48:32 +02:00
attempt to make updating clients via websocket faster
This commit is contained in:
parent
dc063983ea
commit
eb8c296e62
@ -795,7 +795,7 @@ ws.subscribeToOutsideSyncMessages(async syncData => {
|
|||||||
syncData.filter(sync => sync.entityName === 'attributes').forEach(sync => {
|
syncData.filter(sync => sync.entityName === 'attributes').forEach(sync => {
|
||||||
const note = treeCache.notes[sync.noteId];
|
const note = treeCache.notes[sync.noteId];
|
||||||
|
|
||||||
if (note && note.attributeCache) {
|
if (note && note.__attributeCache) {
|
||||||
noteIdsToRefresh.add(sync.entityId);
|
noteIdsToRefresh.add(sync.entityId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -869,7 +869,7 @@ async function reloadNotes(noteIds, activateNotePath = null) {
|
|||||||
if (activateNotePath) {
|
if (activateNotePath) {
|
||||||
const node = await getNodeFromPath(activateNotePath);
|
const node = await getNodeFromPath(activateNotePath);
|
||||||
|
|
||||||
if (node) {
|
if (node && !node.isActive()) {
|
||||||
await node.setActive(true);
|
await node.setActive(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@ const outsideSyncMessageHandlers = [];
|
|||||||
const messageHandlers = [];
|
const messageHandlers = [];
|
||||||
|
|
||||||
let ws;
|
let ws;
|
||||||
let lastSyncId = window.glob.maxSyncIdAtLoad;
|
let lastAcceptedSyncId = window.glob.maxSyncIdAtLoad;
|
||||||
|
let lastProcessedSyncId = window.glob.maxSyncIdAtLoad;
|
||||||
let lastPingTs;
|
let lastPingTs;
|
||||||
let syncDataQueue = [];
|
let syncDataQueue = [];
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ async function handleMessage(event) {
|
|||||||
let syncIdReachedListeners = [];
|
let syncIdReachedListeners = [];
|
||||||
|
|
||||||
function waitForSyncId(desiredSyncId) {
|
function waitForSyncId(desiredSyncId) {
|
||||||
if (desiredSyncId <= lastSyncId) {
|
if (desiredSyncId <= lastProcessedSyncId) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,14 +100,14 @@ function waitForSyncId(desiredSyncId) {
|
|||||||
|
|
||||||
function checkSyncIdListeners() {
|
function checkSyncIdListeners() {
|
||||||
syncIdReachedListeners
|
syncIdReachedListeners
|
||||||
.filter(l => l.desiredSyncId <= lastSyncId)
|
.filter(l => l.desiredSyncId <= lastProcessedSyncId)
|
||||||
.forEach(l => l.resolvePromise());
|
.forEach(l => l.resolvePromise());
|
||||||
|
|
||||||
syncIdReachedListeners = syncIdReachedListeners
|
syncIdReachedListeners = syncIdReachedListeners
|
||||||
.filter(l => l.desiredSyncId > lastSyncId);
|
.filter(l => l.desiredSyncId > lastProcessedSyncId);
|
||||||
|
|
||||||
syncIdReachedListeners.filter(l => Date.now() > l.start - 60000)
|
syncIdReachedListeners.filter(l => Date.now() > l.start - 60000)
|
||||||
.forEach(l => console.log(`Waiting for syncId ${l.desiredSyncId} while current is ${lastSyncId} for ${Math.floor((Date.now() - l.start) / 1000)}s`));
|
.forEach(l => console.log(`Waiting for syncId ${l.desiredSyncId} while current is ${lastProcessedSyncId} for ${Math.floor((Date.now() - l.start) / 1000)}s`));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function consumeSyncData() {
|
async function consumeSyncData() {
|
||||||
@ -116,13 +117,17 @@ async function consumeSyncData() {
|
|||||||
|
|
||||||
const outsideSyncData = allSyncData.filter(sync => sync.sourceId !== glob.sourceId);
|
const outsideSyncData = allSyncData.filter(sync => sync.sourceId !== glob.sourceId);
|
||||||
|
|
||||||
|
// we set lastAcceptedSyncId even before sync processing and send ping so that backend can start sending more updates
|
||||||
|
lastAcceptedSyncId = Math.max(lastAcceptedSyncId, allSyncData[allSyncData.length - 1].id);
|
||||||
|
sendPing();
|
||||||
|
|
||||||
// the update process should be synchronous as a whole but individual handlers can run in parallel
|
// the update process should be synchronous as a whole but individual handlers can run in parallel
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
...allSyncMessageHandlers.map(syncHandler => syncHandler(allSyncData)),
|
...allSyncMessageHandlers.map(syncHandler => syncHandler(allSyncData)),
|
||||||
...outsideSyncMessageHandlers.map(syncHandler => syncHandler(outsideSyncData))
|
...outsideSyncMessageHandlers.map(syncHandler => syncHandler(outsideSyncData))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
lastSyncId = allSyncData[allSyncData.length - 1].id;
|
lastProcessedSyncId = Math.max(lastProcessedSyncId, allSyncData[allSyncData.length - 1].id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,29 +145,32 @@ function connectWebSocket() {
|
|||||||
return ws;
|
return ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function sendPing() {
|
||||||
|
if (Date.now() - lastPingTs > 30000) {
|
||||||
|
console.log(utils.now(), "Lost connection to server");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ws.readyState === ws.OPEN) {
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: 'ping',
|
||||||
|
lastSyncId: lastAcceptedSyncId
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else if (ws.readyState === ws.CLOSED || ws.readyState === ws.CLOSING) {
|
||||||
|
console.log(utils.now(), "WS closed or closing, trying to reconnect");
|
||||||
|
|
||||||
|
ws = connectWebSocket();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ws = connectWebSocket();
|
ws = connectWebSocket();
|
||||||
|
|
||||||
lastSyncId = glob.maxSyncIdAtLoad;
|
lastAcceptedSyncId = glob.maxSyncIdAtLoad;
|
||||||
|
lastProcessedSyncId = glob.maxSyncIdAtLoad;
|
||||||
lastPingTs = Date.now();
|
lastPingTs = Date.now();
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(sendPing, 1000);
|
||||||
if (Date.now() - lastPingTs > 30000) {
|
|
||||||
console.log(utils.now(), "Lost connection to server");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ws.readyState === ws.OPEN) {
|
|
||||||
ws.send(JSON.stringify({
|
|
||||||
type: 'ping',
|
|
||||||
lastSyncId: lastSyncId
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
else if (ws.readyState === ws.CLOSED || ws.readyState === ws.CLOSING) {
|
|
||||||
console.log(utils.now(), "WS closed or closing, trying to reconnect");
|
|
||||||
|
|
||||||
ws = connectWebSocket();
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
subscribeToMessages(message => {
|
subscribeToMessages(message => {
|
||||||
|
@ -125,7 +125,8 @@ async function getEditedNotesOnDate(req) {
|
|||||||
SELECT noteId FROM note_revisions
|
SELECT noteId FROM note_revisions
|
||||||
WHERE note_revisions.dateLastEdited LIKE '${date}%'
|
WHERE note_revisions.dateLastEdited LIKE '${date}%'
|
||||||
)
|
)
|
||||||
ORDER BY isDeleted`);
|
ORDER BY isDeleted
|
||||||
|
LIMIT 50`);
|
||||||
|
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
const notePath = noteCacheService.getNotePath(note.noteId);
|
const notePath = noteCacheService.getNotePath(note.noteId);
|
||||||
|
@ -4,13 +4,25 @@ const dateUtils = require('./date_utils');
|
|||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
const cls = require('./cls');
|
const cls = require('./cls');
|
||||||
|
|
||||||
|
let syncs = [];
|
||||||
|
|
||||||
async function addEntitySync(entityName, entityId, sourceId) {
|
async function addEntitySync(entityName, entityId, sourceId) {
|
||||||
await sql.replace("sync", {
|
const sync = {
|
||||||
entityName: entityName,
|
entityName: entityName,
|
||||||
entityId: entityId,
|
entityId: entityId,
|
||||||
utcSyncDate: dateUtils.utcNowDateTime(),
|
utcSyncDate: dateUtils.utcNowDateTime(),
|
||||||
sourceId: sourceId || cls.getSourceId() || sourceIdService.getCurrentSourceId()
|
sourceId: sourceId || cls.getSourceId() || sourceIdService.getCurrentSourceId()
|
||||||
});
|
};
|
||||||
|
|
||||||
|
sync.id = await sql.replace("sync", sync);
|
||||||
|
|
||||||
|
syncs.push(sync);
|
||||||
|
|
||||||
|
setTimeout(() => require('./ws').sendPingToAllClients(), 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEntitySyncsNewerThan(syncId) {
|
||||||
|
return syncs.filter(s => s.id > syncId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cleanupSyncRowsForMissingEntities(entityName, entityKey) {
|
async function cleanupSyncRowsForMissingEntities(entityName, entityKey) {
|
||||||
@ -83,5 +95,6 @@ module.exports = {
|
|||||||
addAttributeSync: async (attributeId, sourceId) => await addEntitySync("attributes", attributeId, sourceId),
|
addAttributeSync: async (attributeId, sourceId) => await addEntitySync("attributes", attributeId, sourceId),
|
||||||
addApiTokenSync: async (apiTokenId, sourceId) => await addEntitySync("api_tokens", apiTokenId, sourceId),
|
addApiTokenSync: async (apiTokenId, sourceId) => await addEntitySync("api_tokens", apiTokenId, sourceId),
|
||||||
addEntitySync,
|
addEntitySync,
|
||||||
fillAllSyncRows
|
fillAllSyncRows,
|
||||||
|
getEntitySyncsNewerThan
|
||||||
};
|
};
|
@ -5,6 +5,7 @@ const sql = require('./sql');
|
|||||||
const syncMutexService = require('./sync_mutex');
|
const syncMutexService = require('./sync_mutex');
|
||||||
|
|
||||||
let webSocketServer;
|
let webSocketServer;
|
||||||
|
let lastAcceptedSyncIds = {};
|
||||||
|
|
||||||
function init(httpServer, sessionParser) {
|
function init(httpServer, sessionParser) {
|
||||||
webSocketServer = new WebSocket.Server({
|
webSocketServer = new WebSocket.Server({
|
||||||
@ -23,7 +24,11 @@ function init(httpServer, sessionParser) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
webSocketServer.on('connection', (ws, req) => {
|
webSocketServer.on('connection', (ws, req) => {
|
||||||
console.log("websocket client connected");
|
ws.id = utils.randomString(10);
|
||||||
|
|
||||||
|
lastAcceptedSyncIds[ws.id] = 0;
|
||||||
|
|
||||||
|
console.log(`websocket client connected`);
|
||||||
|
|
||||||
ws.on('message', messageJson => {
|
ws.on('message', messageJson => {
|
||||||
const message = JSON.parse(messageJson);
|
const message = JSON.parse(messageJson);
|
||||||
@ -32,7 +37,9 @@ function init(httpServer, sessionParser) {
|
|||||||
log.error('JS Error: ' + message.error);
|
log.error('JS Error: ' + message.error);
|
||||||
}
|
}
|
||||||
else if (message.type === 'ping') {
|
else if (message.type === 'ping') {
|
||||||
syncMutexService.doExclusively(async () => await sendPing(ws, message.lastSyncId));
|
lastAcceptedSyncIds[ws.id] = message.lastSyncId;
|
||||||
|
|
||||||
|
syncMutexService.doExclusively(async () => await sendPing(ws));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.error('Unrecognized message: ');
|
log.error('Unrecognized message: ');
|
||||||
@ -64,8 +71,8 @@ function sendMessageToAllClients(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendPing(client, lastSentSyncId) {
|
async function sendPing(client) {
|
||||||
const syncData = await sql.getRows("SELECT * FROM sync WHERE id > ?", [lastSentSyncId]);
|
const syncData = require('./sync_table').getEntitySyncsNewerThan(lastAcceptedSyncIds[client.id]);
|
||||||
|
|
||||||
for (const sync of syncData) {
|
for (const sync of syncData) {
|
||||||
// fill in some extra data needed by the frontend
|
// fill in some extra data needed by the frontend
|
||||||
@ -92,6 +99,14 @@ async function sendPing(client, lastSentSyncId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function sendPingToAllClients() {
|
||||||
|
if (webSocketServer) {
|
||||||
|
webSocketServer.clients.forEach(function each(client) {
|
||||||
|
sendPing(client);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function refreshTree() {
|
function refreshTree() {
|
||||||
sendMessageToAllClients({ type: 'refresh-tree' });
|
sendMessageToAllClients({ type: 'refresh-tree' });
|
||||||
}
|
}
|
||||||
@ -109,5 +124,6 @@ module.exports = {
|
|||||||
sendMessageToAllClients,
|
sendMessageToAllClients,
|
||||||
refreshTree,
|
refreshTree,
|
||||||
syncPullInProgress,
|
syncPullInProgress,
|
||||||
syncPullFinished
|
syncPullFinished,
|
||||||
|
sendPingToAllClients
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user