mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
[bug] Add internal/cluster/pre-stop handler to graceful shutdown in k8s cluster
This commit is contained in:
@ -175,6 +175,7 @@ const lockDocumentsTimerId = {}; //to drop connection that can't unlockDocument
|
||||
let pubsub;
|
||||
let queue;
|
||||
let shutdownFlag = false;
|
||||
let preStopFlag = false;
|
||||
const expDocumentsStep = gc.getCronStep(cfgExpDocumentsCron);
|
||||
|
||||
const MIN_SAVE_EXPIRATION = 60000;
|
||||
@ -191,6 +192,10 @@ function getIsShutdown() {
|
||||
return shutdownFlag;
|
||||
}
|
||||
|
||||
function getIsPreStop() {
|
||||
return preStopFlag;
|
||||
}
|
||||
|
||||
function getEditorConfig(ctx) {
|
||||
let tenEditor = ctx.getCfg('services.CoAuthoring.editor', cfgEditor);
|
||||
tenEditor = JSON.parse(JSON.stringify(tenEditor));
|
||||
@ -1534,7 +1539,7 @@ function* cleanDocumentOnExit(ctx, docId, deleteChanges, opt_userIndex) {
|
||||
|
||||
//clean redis (redisKeyPresenceSet and redisKeyPresenceHash removed with last element)
|
||||
yield editorData.cleanDocumentOnExit(ctx, docId);
|
||||
if (editorStatProxy?.deleteKey) {
|
||||
if (preStopFlag && editorStatProxy?.deleteKey) {
|
||||
yield editorStatProxy.deleteKey(docId);
|
||||
}
|
||||
//remove changes
|
||||
@ -1772,6 +1777,7 @@ exports.hasEditors = hasEditors;
|
||||
exports.getEditorsCountPromise = co.wrap(getEditorsCount);
|
||||
exports.getCallback = getCallback;
|
||||
exports.getIsShutdown = getIsShutdown;
|
||||
exports.getIsPreStop = getIsPreStop;
|
||||
exports.hasChanges = hasChanges;
|
||||
exports.cleanDocumentOnExitPromise = co.wrap(cleanDocumentOnExit);
|
||||
exports.cleanDocumentOnExitNoChangesPromise = co.wrap(cleanDocumentOnExitNoChanges);
|
||||
@ -2178,7 +2184,7 @@ exports.install = function (server, app, callbackFunction) {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (hvals?.length <= 0 && editorStatProxy?.deleteKey) {
|
||||
if (preStopFlag && hvals?.length <= 0 && editorStatProxy?.deleteKey) {
|
||||
yield editorStatProxy.deleteKey(docId);
|
||||
}
|
||||
}
|
||||
@ -4214,9 +4220,12 @@ exports.install = function (server, app, callbackFunction) {
|
||||
ctx.initFromConnection(conn);
|
||||
//todo group by tenant
|
||||
yield ctx.initTenantCache();
|
||||
const tenExpSessionIdle = ms(ctx.getCfg('services.CoAuthoring.expire.sessionidle', cfgExpSessionIdle));
|
||||
let tenExpSessionIdle = ms(ctx.getCfg('services.CoAuthoring.expire.sessionidle', cfgExpSessionIdle)) || 0;
|
||||
const tenExpSessionAbsolute = ms(ctx.getCfg('services.CoAuthoring.expire.sessionabsolute', cfgExpSessionAbsolute));
|
||||
const tenExpSessionCloseCommand = ms(ctx.getCfg('services.CoAuthoring.expire.sessionclosecommand', cfgExpSessionCloseCommand));
|
||||
if (preStopFlag && (tenExpSessionIdle > 5 * 60 * 1000 || tenExpSessionIdle <= 0)) {
|
||||
tenExpSessionIdle = 5 * 60 * 1000; //5 minutes
|
||||
}
|
||||
|
||||
const maxMs = nowMs + Math.max(tenExpSessionCloseCommand, expDocumentsStep);
|
||||
let tenant = tenants[ctx.tenant];
|
||||
@ -4732,6 +4741,26 @@ exports.shutdown = function (req, res) {
|
||||
}
|
||||
});
|
||||
};
|
||||
exports.preStop = async function (req, res) {
|
||||
let output = false;
|
||||
const ctx = new operationContext.Context();
|
||||
try {
|
||||
ctx.initFromRequest(req);
|
||||
await ctx.initTenantCache();
|
||||
preStopFlag = req.method === 'PUT';
|
||||
ctx.logger.info('preStop set flag', preStopFlag);
|
||||
if (preStopFlag) {
|
||||
await gc.checkFileExpire(0);
|
||||
}
|
||||
output = true;
|
||||
} catch (err) {
|
||||
ctx.logger.error('preStop error %s', err.stack);
|
||||
} finally {
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.send(output.toString());
|
||||
ctx.logger.info('preStop end');
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Get active connections array
|
||||
* @returns {Array} Active connections
|
||||
|
||||
@ -467,6 +467,9 @@ const cleanupCache = co.wrap(function* (ctx, docId) {
|
||||
const removeRes = yield taskResult.remove(ctx, docId);
|
||||
if (removeRes.affectedRows > 0) {
|
||||
yield storage.deletePath(ctx, docId);
|
||||
if (docsCoServer?.editorStatProxy?.deleteKey) {
|
||||
yield docsCoServer.editorStatProxy.deleteKey(docId);
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
ctx.logger.debug('cleanupCache docId=%s db.affectedRows=%d', docId, removeRes.affectedRows);
|
||||
@ -479,6 +482,9 @@ const cleanupCacheIf = co.wrap(function* (ctx, mask) {
|
||||
if (removeRes.affectedRows > 0) {
|
||||
sqlBase.deleteChanges(ctx, mask.key, null);
|
||||
yield storage.deletePath(ctx, mask.key);
|
||||
if (docsCoServer?.editorStatProxy?.deleteKey) {
|
||||
yield docsCoServer.editorStatProxy.deleteKey(mask.key);
|
||||
}
|
||||
res = true;
|
||||
}
|
||||
ctx.logger.debug('cleanupCacheIf db.affectedRows=%d', removeRes.affectedRows);
|
||||
@ -1300,7 +1306,7 @@ const commandSfcCallback = co.wrap(function* (ctx, cmd, isSfcm, isEncrypted) {
|
||||
//todo simultaneous opening
|
||||
//clean redis (redisKeyPresenceSet and redisKeyPresenceHash removed with last element)
|
||||
yield docsCoServer.editorData.cleanDocumentOnExit(ctx, docId);
|
||||
if (docsCoServer?.editorStatProxy?.deleteKey) {
|
||||
if (docsCoServer.getIsPreStop() && docsCoServer?.editorStatProxy?.deleteKey) {
|
||||
yield docsCoServer.editorStatProxy.deleteKey(docId);
|
||||
}
|
||||
//to unlock wopi file
|
||||
|
||||
@ -274,6 +274,9 @@ docsCoServer.install(server, app, () => {
|
||||
app.use('/info', infoRouter(docsCoServer.getConnections));
|
||||
app.put('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
|
||||
app.delete('/internal/cluster/inactive', utils.checkClientIp, docsCoServer.shutdown);
|
||||
app.put('/internal/cluster/pre-stop', utils.checkClientIp, docsCoServer.preStop);
|
||||
app.delete('/internal/cluster/pre-stop', utils.checkClientIp, docsCoServer.preStop);
|
||||
|
||||
app.get('/internal/connections/edit', docsCoServer.getEditorConnectionsCount);
|
||||
|
||||
function checkWopiEnable(req, res, next) {
|
||||
|
||||
Reference in New Issue
Block a user