From 5cfdfd6e9cb96ffba1f9b0f0c21041683037262b Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 18 Sep 2019 22:03:31 +1000 Subject: [PATCH] Moves temp file cleanup to a background task --- src/Umbraco.Web/Editors/TinyMceController.cs | 18 ----- src/Umbraco.Web/Scheduling/LogScrubber.cs | 4 +- .../Scheduling/SchedulerComponent.cs | 17 +++++ src/Umbraco.Web/Scheduling/TempFileCleanup.cs | 75 +++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../FileUploadCleanupFilterAttribute.cs | 22 ------ 6 files changed, 94 insertions(+), 43 deletions(-) create mode 100644 src/Umbraco.Web/Scheduling/TempFileCleanup.cs diff --git a/src/Umbraco.Web/Editors/TinyMceController.cs b/src/Umbraco.Web/Editors/TinyMceController.cs index 601095bd24..c6c1acd048 100644 --- a/src/Umbraco.Web/Editors/TinyMceController.cs +++ b/src/Umbraco.Web/Editors/TinyMceController.cs @@ -104,24 +104,6 @@ namespace Umbraco.Web.Editors return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, $"Error when trying to move {currentFile} to {newFilePath}", ex); } - // Now remove all old files so that the temp folder(s) never grow - // Anything older than one day gets deleted - var tempFiles = Directory.GetFiles(IOHelper.MapPath(SystemDirectories.TempFileUploads), "*", SearchOption.AllDirectories); - foreach (var tempFile in tempFiles) - { - if (DateTime.UtcNow - File.GetLastWriteTimeUtc(tempFile) > TimeSpan.FromDays(1)) - { - try - { - File.Delete(tempFile); - } - catch (Exception ex) - { - Logger.Error(ex, "Could not delete temp file {FileName}", tempFile); - } - } - } - return Request.CreateResponse(HttpStatusCode.OK, new { tmpLocation = relativeNewFilePath }); } } diff --git a/src/Umbraco.Web/Scheduling/LogScrubber.cs b/src/Umbraco.Web/Scheduling/LogScrubber.cs index c39f9df1b3..db13a80f9b 100644 --- a/src/Umbraco.Web/Scheduling/LogScrubber.cs +++ b/src/Umbraco.Web/Scheduling/LogScrubber.cs @@ -1,16 +1,14 @@ using System; -using System.Threading; -using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Sync; namespace Umbraco.Web.Scheduling { + internal class LogScrubber : RecurringTaskBase { private readonly IRuntimeState _runtime; diff --git a/src/Umbraco.Web/Scheduling/SchedulerComponent.cs b/src/Umbraco.Web/Scheduling/SchedulerComponent.cs index 5e29b17f56..c334bcee1a 100644 --- a/src/Umbraco.Web/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Web/Scheduling/SchedulerComponent.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; using Umbraco.Core.Services; @@ -29,6 +31,7 @@ namespace Umbraco.Web.Scheduling private BackgroundTaskRunner _publishingRunner; private BackgroundTaskRunner _tasksRunner; private BackgroundTaskRunner _scrubberRunner; + private BackgroundTaskRunner _fileCleanupRunner; private BackgroundTaskRunner _healthCheckRunner; private bool _started; @@ -58,6 +61,7 @@ namespace Umbraco.Web.Scheduling _publishingRunner = new BackgroundTaskRunner("ScheduledPublishing", _logger); _tasksRunner = new BackgroundTaskRunner("ScheduledTasks", _logger); _scrubberRunner = new BackgroundTaskRunner("LogScrubber", _logger); + _fileCleanupRunner = new BackgroundTaskRunner("TempFileCleanup", _logger); _healthCheckRunner = new BackgroundTaskRunner("HealthCheckNotifier", _logger); // we will start the whole process when a successful request is made @@ -93,6 +97,7 @@ namespace Umbraco.Web.Scheduling tasks.Add(RegisterKeepAlive()); tasks.Add(RegisterScheduledPublishing()); tasks.Add(RegisterLogScrubber(settings)); + tasks.Add(RegisterTempFileCleanup()); var healthCheckConfig = Current.Configs.HealthChecks(); if (healthCheckConfig.NotificationSettings.Enabled) @@ -154,5 +159,17 @@ namespace Umbraco.Web.Scheduling _scrubberRunner.TryAdd(task); return task; } + + private IBackgroundTask RegisterTempFileCleanup() + { + // temp file cleanup, will run on all servers - even though file upload should only be handled on the master, this will + // ensure that in the case it happes on replicas that they are cleaned up. + var task = new TempFileCleanup(_fileCleanupRunner, 60000, 3600000 /* 1 hr */, + new[] { new DirectoryInfo(IOHelper.MapPath(SystemDirectories.TempFileUploads)) }, + TimeSpan.FromDays(1), //files that are over a day old + _runtime, _logger); + _scrubberRunner.TryAdd(task); + return task; + } } } diff --git a/src/Umbraco.Web/Scheduling/TempFileCleanup.cs b/src/Umbraco.Web/Scheduling/TempFileCleanup.cs new file mode 100644 index 0000000000..5d28bbfdb1 --- /dev/null +++ b/src/Umbraco.Web/Scheduling/TempFileCleanup.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Logging; + +namespace Umbraco.Web.Scheduling +{ + /// + /// Used to cleanup temporary file locations + /// + internal class TempFileCleanup : RecurringTaskBase + { + private readonly DirectoryInfo[] _tempFolders; + private readonly TimeSpan _age; + private readonly IRuntimeState _runtime; + private readonly IProfilingLogger _logger; + + public TempFileCleanup(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, + IEnumerable tempFolders, TimeSpan age, + IRuntimeState runtime, IProfilingLogger logger) + : base(runner, delayMilliseconds, periodMilliseconds) + { + //SystemDirectories.TempFileUploads + + _tempFolders = tempFolders.ToArray(); + _age = age; + _runtime = runtime; + _logger = logger; + } + + public override bool PerformRun() + { + // ensure we do not run if not main domain + if (_runtime.IsMainDom == false) + { + _logger.Debug("Does not run if not MainDom."); + return false; // do NOT repeat, going down + } + + foreach (var dir in _tempFolders) + CleanupFolder(dir); + + return true; //repeat + } + + private void CleanupFolder(DirectoryInfo dir) + { + dir.Refresh(); //in case it's changed during runtime + if (!dir.Exists) + { + _logger.Debug("The cleanup folder doesn't exist {Folder}", dir.FullName); + } + + var files = dir.GetFiles("*.*", SearchOption.AllDirectories); + foreach (var file in files) + { + if (DateTime.UtcNow - file.LastWriteTimeUtc > _age) + { + try + { + file.Delete(); + } + catch (Exception ex) + { + _logger.Error(ex, "Could not delete temp file {FileName}", file.FullName); + } + } + } + } + + public override bool IsAsync => false; + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c6945a6b15..166eeba352 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -236,6 +236,7 @@ + diff --git a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs index 6e6ec35b1b..1646c8a426 100644 --- a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs @@ -146,28 +146,6 @@ namespace Umbraco.Web.WebApi.Filters Current.Logger.Warn("The actionExecutedContext.Request.Content is not ObjectContent, it is {RequestObjectType}", actionExecutedContext.Request.Content.GetType()); } } - - //Now remove all old files so that the temp folder(s) never grow - foreach (var tempFolder in tempFolders.Distinct()) - { - var files = Directory.GetFiles(tempFolder); - foreach (var file in files) - { - if (DateTime.UtcNow - File.GetLastWriteTimeUtc(file) > TimeSpan.FromDays(1)) - { - try - { - File.Delete(file); - } - catch (System.Exception ex) - { - Current.Logger.Error(ex, "Could not delete temp file {FileName}", file); - } - } - } - - } - } } }