Skip to content
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 Retry and skip logic in AppleMediaImporter #1329

Merged
merged 2 commits into from Jan 29, 2024

Conversation

yy9669
Copy link
Collaborator

@yy9669 yy9669 commented Jan 19, 2024

The major difficulty I met is that the IdempotentExecutor used by CallableImporter cannot be a retryable executor, so I have to use a different retryable executor in AppleMediaImporter itself.

  • Use retryable executor in AppleMediaImporter
  • Add Apple Photos error prefix to all errors thrown by AppleMediaInterface
  • Please help add the following Apple retry strategy to the yaml config:
    • Skippable: ".*APPLE PHOTOS IMPORT: Fail to upload content.*" , ".*APPLE PHOTOS IMPORT: Fail to create album.*", ".*APPLE PHOTOS IMPORT: Fail to create media.*", ".*APPLE PHOTOS IMPORT: Fail to get upload url.*"
    • Non-Retryable: ".*APPLE PHOTOS IMPORT: iCloud Photos Library not found.*", ".*APPLE PHOTOS IMPORT: iCloud Storage is full.*"

@yy9669 yy9669 force-pushed the skipContentFailureAppleImport branch 2 times, most recently from 82e5bd7 to 6f189a7 Compare January 19, 2024 01:00
@kateyeo
Copy link
Collaborator

kateyeo commented Jan 22, 2024

Hi Xuyang, just saw this, I'll review it today


Collection<ErrorDetail> errors = idempotentExecutor.getRecentErrors();
if (!errors.isEmpty() && executor instanceof RetryingInMemoryIdempotentImportExecutor) { // throw the error for retryExecutor to retry, only include the actual error message, but not the stack traces
throw new IOException(errors.iterator().hasNext() ? errors.iterator().next().exception().lines().findFirst().get() : ApplePhotosConstants.APPLE_PHOTOS_IMPORT_ERROR_PREFIX + " Unknown Error");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we not want to throw the entire stack trace? Is this logic necessary? Can we not just let the errors be thrown by the executor?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we let the error be thrown by idempotentExecutor midway of the import, then it will fail the whole batch even if only one file failed.
Here we throw after the importResult was updated, and the importResult will include all the files except for the failed one.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the way your setting it up here makes sense, but is there a reason you are not including the stack trace?

Copy link
Collaborator Author

@yy9669 yy9669 Jan 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh just in order to make regex look simpler in Retry config

Comment on lines 446 to 455
monitor.severe(
() -> "Error importing album: ",
() -> "Fail to create album: ",
AuditKeys.jobId, jobId,
AuditKeys.albumId, mediaAlbum.getId(),
AuditKeys.errorCode, newPhotoAlbumResponse.getStatus().getCode());

throw new IOException(
throw new IOException(getApplePhotosImportThrowingMessage(
String.format(
"Failed to create album, error code: %d",
newPhotoAlbumResponse.getStatus().getCode()));
"Fail to create album, error code: %d",
newPhotoAlbumResponse.getStatus().getCode())));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging & throwing is unnecessary, we should usually only do one of the two.

If we log here, the client which received the error may double-log, or they may throw the error leaving the logs in the stack trace

@osamahan999
Copy link
Collaborator

I'm going to leave the actual review to @kateyeo because I don't understand some parts of this PR.

@yy9669 yy9669 force-pushed the skipContentFailureAppleImport branch from 6f189a7 to f168ec8 Compare January 25, 2024 17:18
Copy link
Collaborator

@kateyeo kateyeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, looking over this and just wanting to make sure I'm understanding how your implementing retrying in this PR. By using the retrying executor on the entire call within importItem() the entire call would be retried if you throw a retry-able exception. As opposed to if you passed in a retrying executor to the individual importAlbums/importAllMedia calls which would allow skipping/retrying to be handled a the item level.

Let me know if you have it set up how you intended or if I'm misunderstanding anything


Collection<ErrorDetail> errors = idempotentExecutor.getRecentErrors();
if (!errors.isEmpty() && executor instanceof RetryingInMemoryIdempotentImportExecutor) { // throw the error for retryExecutor to retry, only include the actual error message, but not the stack traces
throw new IOException(errors.iterator().hasNext() ? errors.iterator().next().exception().lines().findFirst().get() : ApplePhotosConstants.APPLE_PHOTOS_IMPORT_ERROR_PREFIX + " Unknown Error");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the way your setting it up here makes sense, but is there a reason you are not including the stack trace?

@yy9669
Copy link
Collaborator Author

yy9669 commented Jan 26, 2024

Hi, looking over this and just wanting to make sure I'm understanding how your implementing retrying in this PR. By using the retrying executor on the entire call within importItem() the entire call would be retried if you throw a retry-able exception. As opposed to if you passed in a retrying executor to the individual importAlbums/importAllMedia calls which would allow skipping/retrying to be handled a the item level.

Let me know if you have it set up how you intended or if I'm misunderstanding anything

Yes the is intended, I want to retry the whole batch.
All Apple calls are handled in batches, and it's step by step - get upload url, upload to Apple Content, and create metadata.

Sometimes failure in one step is due to corruption in previous step, eg. fail to upload to Apple Content is because we got wrong upload url in previous step, so it's useful to retry from the first step instead of retrying current step multiple times.

Copy link
Collaborator

@kateyeo kateyeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok sounds good, thanks for the response

@jzacsh jzacsh merged commit 8dc02fe into google:master Jan 29, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants