Safe(r)Delete, Safe(r)Move : could have infinite loop of exceptions. Fixed. Limit 3

This commit is contained in:
Robert McRackan 2021-10-12 17:05:01 -04:00
parent 648b84ee55
commit dfa5829cbd
6 changed files with 50 additions and 62 deletions

View file

@ -6,6 +6,7 @@
<ItemGroup>
<PackageReference Include="Dinah.Core" Version="2.0.0.1" />
<PackageReference Include="Polly" Version="7.2.2" />
</ItemGroup>
</Project>

View file

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Dinah.Core;
using Polly;
using Polly.Retry;
namespace FileManager
{
@ -11,8 +13,7 @@ namespace FileManager
private const int MAX_FILENAME_LENGTH = 255;
private const int MAX_DIRECTORY_LENGTH = 247;
//public static string GetValidFilename(string template, Dictionary<string, object> parameters) { }
public static string GetValidFilename(string dirFullPath, string filename, string extension, params string[] metadataSuffixes)
public static string GetValidFilename(string dirFullPath, string filename, string extension, string metadataSuffix)
{
if (string.IsNullOrWhiteSpace(dirFullPath))
throw new ArgumentException($"{nameof(dirFullPath)} may not be null or whitespace", nameof(dirFullPath));
@ -23,13 +24,11 @@ namespace FileManager
filename = filename.Replace(':', '_');
filename = PathLib.ToPathSafeString(filename);
// manage length
if (filename.Length > 50)
filename = filename.Substring(0, 50) + "[...]";
// append metadata
if (metadataSuffixes != null && metadataSuffixes.Length > 0)
filename += " [" + string.Join("][", metadataSuffixes) + "]";
if (!string.IsNullOrWhiteSpace(metadataSuffix))
filename += $" [{metadataSuffix}]";
// extension is null when this method is used for directory names
if (!string.IsNullOrWhiteSpace(extension))
@ -65,7 +64,7 @@ namespace FileManager
public static string Move(string source, string destination)
{
// TODO: destination must be valid path. Use: " (#)" when needed
SafeMove(source, destination);
SaferMove(source, destination);
return destination;
}
@ -75,57 +74,50 @@ namespace FileManager
return path;
}
/// <summary>Delete file. No error when file does not exist.
/// Exceptions are logged, not thrown.</summary>
/// <param name="source">File to delete</param>
public static void SafeDelete(string source)
{
if (!File.Exists(source))
return;
private static int maxRetryAttempts { get; } = 3;
private static TimeSpan pauseBetweenFailures { get; } = TimeSpan.FromMilliseconds(100);
private static RetryPolicy retryPolicy { get; } =
Policy
.Handle<Exception>()
.WaitAndRetry(maxRetryAttempts, i => pauseBetweenFailures);
while (true)
/// <summary>Delete file. No error when source does not exist. Retry up to 3 times.</summary>
public static void SaferDelete(string source)
=> retryPolicy.Execute(() =>
{
try
{
File.Delete(source);
Serilog.Log.Logger.Information($"File successfully deleted: {source}");
break;
}
catch (Exception e)
{
System.Threading.Thread.Sleep(100);
Serilog.Log.Logger.Error(e, $"Failed to delete: {source}");
}
}
}
/// <summary>
/// Moves a specified file to a new location, providing the option to specify a newfile name.
/// Exceptions are logged, not thrown.
/// </summary>
/// <param name="source">The name of the file to move. Can include a relative or absolute path.</param>
/// <param name="target">The new path and name for the file.</param>
public static void SafeMove(string source, string target)
{
while (true)
{
try
{
if (File.Exists(source))
if (!File.Exists(source))
{
SafeDelete(target);
File.Move(source, target);
Serilog.Log.Logger.Information($"File successfully moved from '{source}' to '{target}'");
File.Delete(source);
Serilog.Log.Logger.Information("File successfully deleted", new { source });
}
break;
}
catch (Exception e)
{
System.Threading.Thread.Sleep(100);
Serilog.Log.Logger.Error(e, $"Failed to move '{source}' to '{target}'");
Serilog.Log.Logger.Error(e, "Failed to delete file", new { source });
throw;
}
}
}
});
/// <summary>Move file. No error when source does not exist. Retry up to 3 times.</summary>
public static void SaferMove(string source, string target)
=> retryPolicy.Execute(() =>
{
try
{
if (!File.Exists(source))
{
SaferDelete(target);
File.Move(source, target);
Serilog.Log.Logger.Information("File successfully moved", new { source, target });
}
}
catch (Exception e)
{
Serilog.Log.Logger.Error(e, "Failed to move file", new { source, target });
throw;
}
});
}
}