-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Media cache : A background task to purge all periodically. #8751
Changes from 11 commits
d9ae4b6
623eef7
f18cf8b
730517e
12576c5
2361e2d
d724737
aa204c5
d5608b8
2b9d8f8
d6d7b7e
5d7b72e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
using OrchardCore.BackgroundTasks; | ||
using OrchardCore.Environment.Shell; | ||
using OrchardCore.Media.Core; | ||
|
||
namespace OrchardCore.Media.Services | ||
{ | ||
|
||
// At 12:00 on Monday. | ||
[BackgroundTask(Schedule = "0 12 * * 1", Description = "Performs cleanup operations for ms-cache and is-cache folders periodically.")] | ||
MikeAlhayek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Left for test driving. | ||
//[BackgroundTask(Schedule = "* * * * *", Description = "Performs cleanup operations for ms-cache and is-cache folders periodically.")] | ||
public class MediaCacheBackgroundTask : IBackgroundTask | ||
{ | ||
private readonly IWebHostEnvironment _webHostEnvironment; | ||
private readonly ShellSettings _shellSettings; | ||
private readonly ILogger _logger; | ||
private const int Repeats = 5; | ||
private const int RepeatTime = 5000; | ||
|
||
public MediaCacheBackgroundTask( | ||
IWebHostEnvironment webHostEnvironment, | ||
ShellSettings shellSettings, | ||
ILogger<MediaCacheBackgroundTask> logger) | ||
{ | ||
_webHostEnvironment = webHostEnvironment; | ||
_shellSettings = shellSettings; | ||
_logger = logger; | ||
} | ||
|
||
public Task DoWorkAsync(IServiceProvider serviceProvider, CancellationToken cancellationToken) | ||
{ | ||
_logger.LogInformation("Media cache background task cleaning started"); | ||
|
||
var directoryInfo = new DirectoryInfo(Path.Combine(_webHostEnvironment.WebRootPath, "is-cache")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be using |
||
|
||
// Don't delete is-cache folder. | ||
RecursiveDeleteAsync(directoryInfo, false, cancellationToken); | ||
|
||
directoryInfo = new DirectoryInfo(GetMediaCachePath(_webHostEnvironment, DefaultMediaFileStoreCacheFileProvider.AssetsCachePath, _shellSettings)); | ||
RecursiveDeleteAsync(directoryInfo, false, cancellationToken); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the idea is to purge-all, you should use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would have used that method if that would have worked all the time. The thing I'm trying to do here is to find out why it fails to delete some of these files because of a lock. I don't want to use another service that does that because I don't want to change the service itself. Once, we will have figured out the lock then we will update that service accordingly. |
||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
private async void RecursiveDeleteAsync(DirectoryInfo baseDir, bool deleteBaseDir, CancellationToken cancellationToken) | ||
{ | ||
if (!baseDir.Exists) | ||
{ | ||
return; | ||
} | ||
|
||
try | ||
{ | ||
var dirs = baseDir.EnumerateDirectories().ToArray(); | ||
foreach (var dir in dirs) | ||
{ | ||
try | ||
{ | ||
RecursiveDeleteAsync(dir, true, cancellationToken); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogError(ex, "Error deleting dir {DirName}", dir.Name); | ||
} | ||
} | ||
} | ||
catch (Exception ee) | ||
{ | ||
_logger.LogError(ee, "Error enumerating dirs {DirName}", baseDir.Name); | ||
} | ||
|
||
var files = baseDir.GetFiles(); | ||
foreach (var file in files) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
try | ||
{ | ||
file.IsReadOnly = false; | ||
|
||
if (IsFileLocked(file)) | ||
{ | ||
var i = 0; | ||
while (file.Exists && IsFileLocked(file) && i <= Repeats) | ||
{ | ||
await Task.Delay(RepeatTime, cancellationToken); | ||
file.Delete(); | ||
i++; | ||
} | ||
} | ||
else | ||
{ | ||
file.Delete(); | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogError(e, "Error deleting cache file {FilePath}", file.Name); | ||
} | ||
} | ||
|
||
if (deleteBaseDir) | ||
{ | ||
try | ||
{ | ||
var i = 0; | ||
while (baseDir.Exists && baseDir.GetFiles().Length == 0 && i <= Repeats) | ||
{ | ||
baseDir.Delete(); | ||
await Task.Delay(RepeatTime, cancellationToken); | ||
i++; | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogError(e, "Error deleting cache folder {DirectoryPath}", baseDir.Name); | ||
} | ||
} | ||
} | ||
|
||
private static bool IsFileLocked(FileInfo file) | ||
{ | ||
FileStream stream = null; | ||
|
||
try | ||
{ | ||
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); | ||
} | ||
catch (IOException) | ||
{ | ||
// The file is unavailable because it is: | ||
// still being written to | ||
// or being processed by another thread | ||
// or does not exist (has already been processed). | ||
return true; | ||
} | ||
finally | ||
{ | ||
if (stream != null) | ||
{ | ||
stream.Close(); | ||
Skrypt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
//file is not locked | ||
return false; | ||
} | ||
|
||
private static string GetMediaCachePath(IWebHostEnvironment hostingEnvironment, string assetsPath, ShellSettings shellSettings) | ||
{ | ||
return PathExtensions.Combine(hostingEnvironment.WebRootPath, assetsPath, shellSettings.Name); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.