Cannot stop resumed tasks by checkForExistingDownloads
Opened this issue · 2 comments
Bug Report
iOS Simulator 15.5 (19F70)
Actual Device iPhone 7 15.8.3
Environment
React: 17.0.2
React native: 0.67.5
react-native-background-downloader: 3.2.1
Target Platform:
iOS (15.8.3/15.5)
Expected Behavior
I expect to be able to pause/resume/stop a task coming from checkForExistingDownloads.
Actual Behavior
Once my task is paused and then resumed, I cannot stop it anymore. It's a sort of zombie.
This happens just if I retrieve the tasks with checkForExistingDownloads.
If I store the object in a property of the class, ( this.task = download({... ) and then I execute the pause/resume/stop actions on it, everything works fine.
But if the task is coming from checkForExistingDownloads, as I pause it and then resume it, I cannot stop it.
Trying to stop it multiple times, on the other hand, generates multiple tasks that are as well downloaded in the background.
Steps to Reproduce
- Start the download providing an id.
- Pause the download, retrieving the task by filtering the checkForExistingDownloads result by the provided id.
- Resume the download, again retrieving it from checkForExistingDownloads.
- Stop it, filtering again the checkForExistingDownloads output by the known id.
You'll see the logs and the percentage going on.
Stopping several times the task coming from checkForExistingDownloads doesn't have any effect at all.
Even worst.
I can see from the logs the number of pending tasks increasing (picture in attachment).
From the snack that follows execute these steps:
- startDownload()
- pauseDownload()
- resumeDownload()
- stopDownload()
- eventually to stop all the tasks without any filter by id: stopAllDownloads() that logs the active tasks.
`
const jobId = 'file123';
// Class and state declaration
task = undefined;
startDownload = () => {
this.task = download({
id: jobId,
url: 'https://212.183.159.230/200MB.zip',
destination: ${directories.documents}/200MB.zip
,
metadata: {},
})
.begin(({expectedBytes}: {expectedBytes: number}) => {
this.expectedBytes = expectedBytes;
devLog(Going to download ${expectedBytes} bytes!
);
devLog('Task: ', this.task);
})
.progress(data => {
devLog('Downloaded: ', data);
this.setState({percentage: Number(data) * 100});
})
.done(data => {
devLog('Download is done!', data);
this.task = undefined;
completeHandler(jobId);
})
.error(error => {
this.task = undefined;
devLog('Download canceled due to error: ', error);
});
};
stopDownload = () => {
devLog('stopDownload');
checkForExistingDownloads().then(tasks => {
const task = tasks.find(t => t.id === jobId);
devLog('Stop the task: ', task);
task?.stop();
});
this.setState({percentage: 0});
};
pauseDownload = () => {
devLog('pauseDownload');
checkForExistingDownloads().then(tasks => {
const task = tasks.find(t => t.id === jobId);
devLog('Pause the task: ', task);
task?.pause();
});
};
resumeDownload = () => {
devLog('resumeDownload');
checkForExistingDownloads().then(tasks => {
const task = tasks.find(t => t.id === jobId);
devLog('Resume the task: ', task);
task?.resume();
});
};
stopAllDownloads = async () => {
const tasks = await checkForExistingDownloads();
devLog(
'Stopping all the existing tasks from checkForExistingDownloads:',
tasks.length,
);
for (const task of tasks) {
task.stop();
}
};
// These tasks acting directly to the class property work like a charm:
pauseDownloadByTask = () => {
devLog('Pausing the task: ', this.task);
this.task?.pause();
};
stopDownloadByTask = () => {
devLog('Stopping the task: ', this.task);
this.task?.stop();
};
resumeDownloadByTask = () => {
devLog('Resuming the task: ', this.task);
this.task?.resume();
};
`
01_PAUSE_WORKS.mov
02_RESUME_THEN_STOP_NOT_WORKING.mov
03_STOPPING_AGAIN_NOT_WORKING.mov
Having the same issue:
Decided to not use pause /resume on iOS and when required just stop the task entirely both on Android and iOS.
Also try to only call checkForExistingDownloads from one place in the codebase and call task stop if needed just after.
Based on the documentation checkForExistingDownloads also resume download on iOS so a secondary call may trigger unintended resume
As a suggestion for the library maintainers - consider not to resume download when calling checkForExistingDownloads.