From 88dcb9aa609b0a95c4f2705fd55df91956a748f6 Mon Sep 17 00:00:00 2001 From: mainLink0435 Date: Fri, 5 Jun 2026 20:03:46 +1000 Subject: [PATCH 1/2] fix: make SymlinkDownloader single-shot with existing-link guard --- .../Services/Downloaders/SymlinkDownloader.cs | 60 ++++++++----------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/server/RdtClient.Service/Services/Downloaders/SymlinkDownloader.cs b/server/RdtClient.Service/Services/Downloaders/SymlinkDownloader.cs index 7bfd9db..cb3d12c 100644 --- a/server/RdtClient.Service/Services/Downloaders/SymlinkDownloader.cs +++ b/server/RdtClient.Service/Services/Downloaders/SymlinkDownloader.cs @@ -1,4 +1,4 @@ -using RdtClient.Data.Enums; +using RdtClient.Data.Enums; using RdtClient.Service.Helpers; using Serilog; @@ -6,8 +6,6 @@ namespace RdtClient.Service.Services.Downloaders; public class SymlinkDownloader(String uri, String destinationPath, String path, Provider? clientKind) : IDownloader { - private const Int32 MaxRetries = 10; - private readonly CancellationTokenSource _cancellationToken = new(); private readonly ILogger _logger = Log.ForContext(); @@ -108,44 +106,32 @@ public class SymlinkDownloader(String uri, String destinationPath, String path, potentialFilePaths = potentialFilePaths.Distinct().ToList(); - for (var retryCount = 0; retryCount < MaxRetries; retryCount++) + _logger.Debug($"Searching {rcloneMountPath} for {fileName}..."); + + file = FindFile(rcloneMountPath, potentialFilePaths, fileName); + + if (file == null && searchSubDirectories) { - DownloadProgress?.Invoke(this, - new() - { - BytesDone = retryCount, - BytesTotal = 10, - Speed = 1 - }); + var subDirectories = Directory.GetDirectories(rcloneMountPath, "*.*", SearchOption.TopDirectoryOnly); - _logger.Debug($"Searching {rcloneMountPath} for {fileName} (attempt #{retryCount})..."); - - file = FindFile(rcloneMountPath, potentialFilePaths, fileName); - - if (file == null && searchSubDirectories) + foreach (var subDirectory in subDirectories) { - var subDirectories = Directory.GetDirectories(rcloneMountPath, "*.*", SearchOption.TopDirectoryOnly); + file = FindFile(Path.Combine(rcloneMountPath, subDirectory), potentialFilePaths, fileName); - foreach (var subDirectory in subDirectories) + if (file != null) { - file = FindFile(Path.Combine(rcloneMountPath, subDirectory), potentialFilePaths, fileName); - - if (file != null) - { - break; - } + break; } } - - if (file == null) - { - await Task.Delay(1000 * retryCount); - } - else - { - break; - } } + + DownloadProgress?.Invoke(this, + new() + { + BytesDone = 1, + BytesTotal = 1, + Speed = 0 + }); } if (file == null) @@ -172,7 +158,7 @@ public class SymlinkDownloader(String uri, String destinationPath, String path, if (!result) { - throw new("Could not find file from rclone mount!"); + throw new("Could not create symbolic link!"); } DownloadComplete?.Invoke(this, new()); @@ -229,6 +215,12 @@ public class SymlinkDownloader(String uri, String destinationPath, String path, { try { + if (File.Exists(symlinkPath)) // Symlink already exists from a prior run. + { + _logger.Information($"Symbolic link already exists at {symlinkPath}"); + return true; + } + File.CreateSymbolicLink(symlinkPath, sourcePath); if (File.Exists(symlinkPath)) // Double-check that the link was created From 08ea902c6830eb9da12a481c5d46e39d21fbf203 Mon Sep 17 00:00:00 2001 From: mainLink0435 Date: Fri, 5 Jun 2026 20:04:09 +1000 Subject: [PATCH 2/2] fix: add 60s cooldown between symlink download retries When the symlink downloader cannot find files on the rclone mount (because the CDN hasn't populated yet), wait 60 seconds before retrying to avoid thrashing the mount with repeated searches. --- server/RdtClient.Service/Services/TorrentRunner.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/server/RdtClient.Service/Services/TorrentRunner.cs b/server/RdtClient.Service/Services/TorrentRunner.cs index 0ee1cbd..1c35e4d 100644 --- a/server/RdtClient.Service/Services/TorrentRunner.cs +++ b/server/RdtClient.Service/Services/TorrentRunner.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics; using System.Text.Json; using Aria2NET; @@ -216,9 +216,15 @@ public class TorrentRunner( if (download.RetryCount < download.Torrent.DownloadRetryAttempts) { - Log($"Retrying download", download, download.Torrent); + var retryDelay = download.Torrent.DownloadClient == Data.Enums.DownloadClient.Symlink + ? TimeSpan.FromMinutes(1) + : TimeSpan.Zero; - await downloads.Reset(downloadId); + var retryAt = DateTimeOffset.UtcNow.Add(retryDelay); + + Log($"Retrying download at {retryAt:u}", download, download.Torrent); + + await downloads.Reset(downloadId, retryAt); await downloads.UpdateRetryCount(downloadId, download.RetryCount + 1); } else