-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add mechanism to cancel the operation of uploading directory #75
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
fd60392
Add ability to cancel upload directory operation
ysaito1001 c82303e
Add unit test to verify cancellation of a single upload
ysaito1001 53c1bb2
Add integ tests to verify cancellation of multiple uploads
ysaito1001 5ff9335
Run `cargo fmt` to fix formatting
ysaito1001 55f8ce7
Make integration test behavior more deterministic
ysaito1001 3a4c8b1
Store `Receiver` in the state instead of passing it around
ysaito1001 6c85ac5
Add integration test to verify dropping `UploadObjectsHandle`
ysaito1001 a6fbdcf
Remove unnecessary doc sentence from `OperationCancelled`
ysaito1001 e655aeb
Add comment on why we check if cancel receiver has been updated
ysaito1001 6244d9e
Create cancellation channel internlly in `UploadObjectsContext`
ysaito1001 bee9119
Make one of uploading multiple objects integ tests more reliable
ysaito1001 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -3,10 +3,34 @@ | |||||
* SPDX-License-Identifier: Apache-2.0 | ||||||
*/ | ||||||
|
||||||
use crate::{error::ErrorKind, types::FailedTransferPolicy}; | ||||||
|
||||||
use super::{UploadObjectsContext, UploadObjectsOutput}; | ||||||
use tokio::task; | ||||||
|
||||||
/// Handle for `UploadObjects` operation | ||||||
/// | ||||||
/// # Cancellation | ||||||
/// | ||||||
/// The operation can be cancelled by either by dropping this handle or by calling | ||||||
/// [`Self::abort`]. In both cases, any ongoing tasks will ignore future work and | ||||||
/// will not start processing anything new. However, there are subtle differences | ||||||
/// in how each cancels ongoing tasks. | ||||||
/// | ||||||
/// When the handle is dropped, in-progress tasks will be cancelled at the await | ||||||
/// points where their futures are waiting. This means a particular upload | ||||||
/// operation may be terminated mid-process, without completing the upload or | ||||||
/// calling `AbortMultipartUpload` for multipart uploads (if the upload is | ||||||
/// multipart, as opposed to a simple `PutObject`). In the case of `Drop`, | ||||||
/// tasks will be forcefully terminated, regardless of the `FailedTransferPolicy` | ||||||
/// associated with the handle. | ||||||
/// | ||||||
/// Calling [`Self::abort`], on the other hand, provides more deterministic cancellation | ||||||
/// behavior. If the `FailedTransferPolicy` for the handle is set to `Abort`, the | ||||||
/// individual upload task can either complete the current upload operation or call | ||||||
/// `AbortMultipartUpload` in the case of multipart uploads. Errors encountered during | ||||||
/// `AbortMultipartUpload` will be logged, but will not affect the program's cancellation | ||||||
/// control flow. | ||||||
#[derive(Debug)] | ||||||
#[non_exhaustive] | ||||||
pub struct UploadObjectsHandle { | ||||||
|
@@ -18,13 +42,61 @@ pub struct UploadObjectsHandle { | |||||
|
||||||
impl UploadObjectsHandle { | ||||||
/// Consume the handle and wait for the upload to complete | ||||||
/// | ||||||
/// When the `FailedTransferPolicy` is set to [`FailedTransferPolicy::Abort`], this method | ||||||
/// will return an error if any of the spawned tasks encounter one. The other tasks will | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
/// be canceled, but their cancellations will not be reported as errors by this method; | ||||||
/// they will be logged as errors, instead. | ||||||
/// | ||||||
/// If the `FailedTransferPolicy` is set to [`FailedTransferPolicy::Continue`], the | ||||||
/// [`UploadObjectsOutput`] will include a detailed breakdown, such as the number of | ||||||
/// successful uploads and the number of failed ones. | ||||||
/// | ||||||
// TODO(aws-sdk-rust#1159) - Consider if we want to return failed `AbortMultipartUpload` during cancellation. | ||||||
#[tracing::instrument(skip_all, level = "debug", name = "join-upload-objects-")] | ||||||
pub async fn join(mut self) -> Result<UploadObjectsOutput, crate::error::Error> { | ||||||
// TODO - Consider implementing more sophisticated error handling such as canceling in-progress transfers | ||||||
let mut first_error_to_report = None; | ||||||
while let Some(join_result) = self.tasks.join_next().await { | ||||||
join_result??; | ||||||
let result = join_result.expect("task completed"); | ||||||
if let Err(e) = result { | ||||||
match self.ctx.state.input.failure_policy() { | ||||||
FailedTransferPolicy::Abort | ||||||
if first_error_to_report.is_none() | ||||||
&& e.kind() != &ErrorKind::OperationCancelled => | ||||||
{ | ||||||
first_error_to_report = Some(e); | ||||||
} | ||||||
FailedTransferPolicy::Continue => { | ||||||
tracing::warn!("encountered but dismissed error when the failure policy is `Continue`: {e}") | ||||||
} | ||||||
_ => {} | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
if let Some(e) = first_error_to_report { | ||||||
Err(e) | ||||||
} else { | ||||||
Ok(UploadObjectsOutput::from(self.ctx.state.as_ref())) | ||||||
} | ||||||
} | ||||||
|
||||||
/// Aborts all tasks owned by the handle. | ||||||
/// | ||||||
/// Unlike `Drop`, calling `abort` gracefully shuts down any in-progress tasks. | ||||||
/// Specifically, ongoing upload tasks will be allowed to complete their current work, | ||||||
/// but any future uploads will be ignored. The task of listing directory contents will | ||||||
/// stop yielding new directory contents. | ||||||
pub async fn abort(&mut self) -> Result<(), crate::error::Error> { | ||||||
if self.ctx.state.input.failure_policy() == &FailedTransferPolicy::Abort { | ||||||
if self.ctx.state.cancel_tx.send(true).is_err() { | ||||||
tracing::warn!( | ||||||
"all receiver ends have been dropped, unable to send a cancellation signal" | ||||||
); | ||||||
} | ||||||
while (self.tasks.join_next().await).is_some() {} | ||||||
} | ||||||
|
||||||
Ok(UploadObjectsOutput::from(self.ctx.state.as_ref())) | ||||||
Ok(()) | ||||||
} | ||||||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trivial: Worth mentioning that the operation might already be complete, and we won't delete anything?