fix(downloader): make aria2 reset idempotent

This commit is contained in:
saltbo
2026-06-06 16:04:19 -04:00
parent 976590a0b4
commit 9fe0bb3520
2 changed files with 73 additions and 4 deletions
+30 -4
View File
@@ -144,11 +144,18 @@ func (a Aria2) ResetTask(ctx context.Context, task client.DownloadTask) error {
if !aria2StatusBelongsToTask(status, taskDir, aria2TaskGID(task.ID)) {
continue
}
if err := aria.ForceRemove(status.GID); err != nil {
resetErrs = append(resetErrs, fmt.Errorf("force remove aria2 gid %s: %w", status.GID, err))
removeActive, removeResult := aria2ResetOperations(status)
if removeActive {
err := aria.ForceRemove(status.GID)
if err != nil && !isAria2DownloadNotFound(err) {
resetErrs = append(resetErrs, fmt.Errorf("force remove aria2 gid %s: %w", status.GID, err))
}
}
if err := aria.RemoveDownloadResult(status.GID); err != nil {
resetErrs = append(resetErrs, fmt.Errorf("remove aria2 result %s: %w", status.GID, err))
if removeResult {
err := aria.RemoveDownloadResult(status.GID)
if err != nil && !isAria2DownloadNotFound(err) {
resetErrs = append(resetErrs, fmt.Errorf("remove aria2 result %s: %w", status.GID, err))
}
}
}
if err := os.RemoveAll(taskDir); err != nil {
@@ -157,6 +164,25 @@ func (a Aria2) ResetTask(ctx context.Context, task client.DownloadTask) error {
return errors.Join(resetErrs...)
}
func aria2ResetOperations(status arigo.Status) (removeActive bool, removeResult bool) {
switch string(status.Status) {
case string(arigo.StatusCompleted), string(arigo.StatusError), string(arigo.StatusRemoved), "complete":
return false, true
case string(arigo.StatusActive), string(arigo.StatusWaiting), string(arigo.StatusPaused):
return true, true
default:
return true, true
}
}
func isAria2DownloadNotFound(err error) bool {
if err == nil {
return false
}
msg := strings.ToLower(err.Error())
return strings.Contains(msg, "download") && strings.Contains(msg, "not found")
}
func (a Aria2) SaveSession(ctx context.Context) error {
client, err := a.client(ctx)
if err != nil {
+43
View File
@@ -150,6 +150,49 @@ func TestAria2StartArgsForceSaveCompletedSeeds(t *testing.T) {
}
}
func TestAria2ResetOperations(t *testing.T) {
tests := []struct {
name string
status arigo.DownloadStatus
wantRemoveActive bool
wantRemoveResult bool
}{
{name: "active", status: arigo.StatusActive, wantRemoveActive: true, wantRemoveResult: true},
{name: "waiting", status: arigo.StatusWaiting, wantRemoveActive: true, wantRemoveResult: true},
{name: "paused", status: arigo.StatusPaused, wantRemoveActive: true, wantRemoveResult: true},
{name: "completed", status: arigo.StatusCompleted, wantRemoveActive: false, wantRemoveResult: true},
{name: "error", status: arigo.StatusError, wantRemoveActive: false, wantRemoveResult: true},
{name: "removed", status: arigo.StatusRemoved, wantRemoveActive: false, wantRemoveResult: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
removeActive, removeResult := aria2ResetOperations(arigo.Status{Status: tt.status})
if removeActive != tt.wantRemoveActive || removeResult != tt.wantRemoveResult {
t.Fatalf(
"expected removeActive=%v removeResult=%v, got removeActive=%v removeResult=%v",
tt.wantRemoveActive,
tt.wantRemoveResult,
removeActive,
removeResult,
)
}
})
}
}
func TestIsAria2DownloadNotFound(t *testing.T) {
if !isAria2DownloadNotFound(errors.New("Active Download not found for GID#b384ccaa7eae88da")) {
t.Fatal("expected aria2 active download not found to be ignored during reset")
}
if !isAria2DownloadNotFound(errors.New("Download result not found for GID#b384ccaa7eae88da")) {
t.Fatal("expected aria2 download result not found to be ignored during reset")
}
if isAria2DownloadNotFound(errors.New("aria2 download ended with status error")) {
t.Fatal("expected ordinary aria2 download errors to stay visible")
}
}
func TestHTTPDownloadResumesExistingFile(t *testing.T) {
var rangeHeader string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {