diff --git a/src/backups.js b/src/backups.js index c17f08408..16ac42ca1 100644 --- a/src/backups.js +++ b/src/backups.js @@ -1216,21 +1216,27 @@ function startBackupTask(auditSource, callback) { let error = locker.lock(locker.OP_FULL_BACKUP); if (error) return callback(new BoxError(BoxError.BAD_STATE, `Cannot backup now: ${error.message}`)); - tasks.add(tasks.TASK_BACKUP, [ ], function (error, taskId) { + settings.getBackupConfig(function (error, backupConfig) { if (error) return callback(error); - eventlog.add(eventlog.ACTION_BACKUP_START, auditSource, { taskId }); + const memoryLimit = 'memoryLimit' in backupConfig ? Math.max(backupConfig.memoryLimit/1024/1024, 400) : 400; - tasks.startTask(taskId, { timeout: 12 * 60 * 60 * 1000 /* 12 hours */, nice: 15 }, function (error, backupId) { - locker.unlock(locker.OP_FULL_BACKUP); + tasks.add(tasks.TASK_BACKUP, [ ], function (error, taskId) { + if (error) return callback(error); - const errorMessage = error ? error.message : ''; - const timedOut = error ? error.code === tasks.ETIMEOUT : false; + eventlog.add(eventlog.ACTION_BACKUP_START, auditSource, { taskId }); - eventlog.add(eventlog.ACTION_BACKUP_FINISH, auditSource, { taskId, errorMessage, timedOut, backupId }); + tasks.startTask(taskId, { timeout: 12 * 60 * 60 * 1000 /* 12 hours */, nice: 15, memoryLimit }, function (error, backupId) { + locker.unlock(locker.OP_FULL_BACKUP); + + const errorMessage = error ? error.message : ''; + const timedOut = error ? error.code === tasks.ETIMEOUT : false; + + eventlog.add(eventlog.ACTION_BACKUP_FINISH, auditSource, { taskId, errorMessage, timedOut, backupId }); + }); + + callback(null, taskId); }); - - callback(null, taskId); }); } diff --git a/src/routes/settings.js b/src/routes/settings.js index 1c2cbcf5a..7903f435e 100644 --- a/src/routes/settings.js +++ b/src/routes/settings.js @@ -103,6 +103,15 @@ function setBackupConfig(req, res, next) { if (typeof req.body.syncConcurrency !== 'number') return next(new HttpError(400, 'syncConcurrency must be a positive integer')); if (req.body.syncConcurrency < 1) return next(new HttpError(400, 'syncConcurrency must be a positive integer')); } + if ('copyConcurrency' in req.body) { + if (typeof req.body.copyConcurrency !== 'number') return next(new HttpError(400, 'copyConcurrency must be a positive integer')); + if (req.body.copyConcurrency < 1) return next(new HttpError(400, 'copyConcurrency must be a positive integer')); + } + if ('downloadConcurrency' in req.body) { + if (typeof req.body.downloadConcurrency !== 'number') return next(new HttpError(400, 'downloadConcurrency must be a positive integer')); + if (req.body.downloadConcurrency < 1) return next(new HttpError(400, 'downloadConcurrency must be a positive integer')); + } + if ('memoryLimit' in req.body && typeof req.body.memoryLimit !== 'number') return next(new HttpError(400, 'memoryLimit must be a positive integer')); if (typeof req.body.format !== 'string') return next(new HttpError(400, 'format must be a string')); if ('acceptSelfSignedCerts' in req.body && typeof req.body.acceptSelfSignedCerts !== 'boolean') return next(new HttpError(400, 'format must be a boolean')); diff --git a/src/settings.js b/src/settings.js index df50bf938..1468954d1 100644 --- a/src/settings.js +++ b/src/settings.js @@ -437,7 +437,7 @@ function setBackupCredentials(credentials, callback) { if (error) return callback(error); // preserve these fields - const extra = _.pick(currentConfig, 'retentionPolicy', 'schedulePattern', 'copyConcurrency', 'syncConcurrency'); + const extra = _.pick(currentConfig, 'retentionPolicy', 'schedulePattern', 'copyConcurrency', 'syncConcurrency', 'memoryLimit', 'downloadConcurrency'); const backupConfig = _.extend({}, credentials, extra);