Severity: Info
File
src/Servy.Core/Helpers/Helper.cs
Lines
350-374 (WriteFileAtomicAsync) and 386-410 (WriteFileAtomic)
Issue
The two methods are byte-for-byte the same except the async one awaits a Func<Stream, Task> and the sync one calls an Action<Stream>. Both:
- compute
Path.GetDirectoryName(path) and create the directory if missing,
- write to
path + ".tmp" with FileMode.Create / FileShare.None,
- flush,
File.Move(tmp, path, overwrite: true),
finally-delete the tmp file with the same try/catch swallow.
public static async Task WriteFileAtomicAsync(string path, Func<Stream, Task> writeContent, CancellationToken ct = default) { ... }
public static void WriteFileAtomic (string path, Action<Stream> writeContent) { ... }
Any future change (e.g. honoring a custom temp dir, switching to FileOptions.WriteThrough, adding tracing, fixing the async one's missing ct propagation to Directory.CreateDirectory) will need to be applied twice and will drift.
Suggested fix
Have the sync version delegate to the async one synchronously, or extract the prelude/cleanup into a shared private helper that takes the writer delegate as Func<Stream, ValueTask>:
public static void WriteFileAtomic(string path, Action<Stream> writeContent)
=> WriteFileAtomicCore(path, fs => { writeContent(fs); fs.Flush(); return default; }).GetAwaiter().GetResult();
public static Task WriteFileAtomicAsync(string path, Func<Stream, Task> writeContent, CancellationToken ct = default)
=> WriteFileAtomicCore(path, async fs => { await writeContent(fs); await fs.FlushAsync(ct); }, ct).AsTask();
private static async ValueTask WriteFileAtomicCore(string path, Func<Stream, ValueTask> writer, CancellationToken ct = default) { ... }
Side benefit: the async path will then also flow ct into the directory-creation step, and a single bug fix lands in both.
Severity: Info
File
src/Servy.Core/Helpers/Helper.csLines
350-374 (
WriteFileAtomicAsync) and 386-410 (WriteFileAtomic)Issue
The two methods are byte-for-byte the same except the async one awaits a
Func<Stream, Task>and the sync one calls anAction<Stream>. Both:Path.GetDirectoryName(path)and create the directory if missing,path + ".tmp"withFileMode.Create / FileShare.None,File.Move(tmp, path, overwrite: true),finally-delete the tmp file with the sametry/catchswallow.Any future change (e.g. honoring a custom temp dir, switching to
FileOptions.WriteThrough, adding tracing, fixing the async one's missingctpropagation toDirectory.CreateDirectory) will need to be applied twice and will drift.Suggested fix
Have the sync version delegate to the async one synchronously, or extract the prelude/cleanup into a shared private helper that takes the writer delegate as
Func<Stream, ValueTask>:Side benefit: the async path will then also flow
ctinto the directory-creation step, and a single bug fix lands in both.