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

Retry on 503 #5938

Merged
merged 3 commits into from
Jan 8, 2025
Merged

Retry on 503 #5938

merged 3 commits into from
Jan 8, 2025

Conversation

TheRealFalcon
Copy link
Member

@TheRealFalcon TheRealFalcon commented Dec 20, 2024

Follow-up to #5578

Proposed Commit Message

feat(url_helper): Retry on 503 error

If the server is busy, no need to fail.
Add type hints to adjascent code paths
and necessary refactors.

Fixes GH-5577

Additional Context

Test Steps

Merge type

  • Squash merge using "Proposed Commit Message"
  • Rebase and merge unique commits. Requires commit messages per-commit each referencing the pull request number (#<PR_NUM>)

@@ -33,6 +43,7 @@
LOG = logging.getLogger(__name__)

REDACTED = "REDACTED"
ExceptionCallback = Optional[Callable[["UrlError"], bool]]
Copy link
Member Author

Choose a reason for hiding this comment

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

My goal here is to unify the exception_cb interface used in readurl and wait_for_url as they are currently different.

None of the pre-existing callbacks used the "request_args" argument, and it can also be retrieved from an HTTPError if needed in the future, and calculated it would be harder in wait_for_url(), so I removed it from the callback interface and updated the call points accordingly.

return to_wait


def _handle_error(
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm hoping this wouldn't be hard to extend to also modify future request arguments if ever needed in the future...but...YAGNI

except exceptions.SSLError as e:
# ssl exceptions are not going to get fixed by waiting a
# few seconds
raise UrlError(e, url=url) from e
except exceptions.HTTPError as e:
Copy link
Member Author

Choose a reason for hiding this comment

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

The isinstance() check is silly now that we can use multiple except arms

@@ -639,61 +724,60 @@ def dual_stack(
return (returned_address, return_result)


class HandledResponse(NamedTuple):
Copy link
Member Author

Choose a reason for hiding this comment

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

I don't love this honestly, but it provides a more structured way of return stuff from the nested functions in wait_for_url()

@holmanb holmanb self-assigned this Jan 6, 2025
Copy link
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

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

Thanks @TheRealFalcon, this looks really close. I left a couple of comments inline.

@@ -653,19 +655,23 @@ def _imds_exception_cb(self, msg, exception=None):
temporarily unroutable or unavailable will still retry due to the
callsite wait_for_url.
"""
if isinstance(exception, uhelp.UrlError):
if exception.code:
Copy link
Member

Choose a reason for hiding this comment

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

Nice cleanup, but this is still redundant. We could eliminate this branch and indent its contents for the same outcome.

Copy link
Member Author

Choose a reason for hiding this comment

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

elif exception.code >= 400: will result in a TypeError, and ways of working around that seems less elegant than this.

cloudinit/url_helper.py Outdated Show resolved Hide resolved
try:
to_wait = float(
time.mktime(
time.strptime(retry_after, "%a, %d %b %Y %H:%M:%S %Z")
Copy link
Member

Choose a reason for hiding this comment

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

eek, parsing!

rfc9110 describes three formats

The preferred format is a fixed-length and single-zone subset of the date and time specification used by the Internet Message Format [RFC5322].

HTTP-date = IMF-fixdate / obs-date

An example of the preferred format is

Sun, 06 Nov 1994 08:49:37 GMT ; IMF-fixdate

Examples of the two obsolete formats are

Sunday, 06-Nov-94 08:49:37 GMT ; obsolete RFC 850 format
Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format

A recipient that parses a timestamp value in an HTTP field MUST accept all three HTTP-date formats.

This implementation fails for an RFC 850 date and ANSI C's asctime() format as well.

Maybe we could just use email.utils.parsedate(), which appears to support all three? It is documented to support RFC 2822, which was obsoleted by RFC 5322, and the source code documents its support for RFC 850.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks!!! I didn't realize the standard library had that (even though it's already used in the same file 😂 ), so I agree, unnecessary manual parsing is bad!

Copy link
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

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

Thanks for putting this together @TheRealFalcon!

@TheRealFalcon TheRealFalcon merged commit 1a51553 into canonical:main Jan 8, 2025
21 of 22 checks passed
@TheRealFalcon TheRealFalcon deleted the retry-on-503 branch January 8, 2025 15:28
TheRealFalcon added a commit that referenced this pull request Jan 13, 2025
If the server is busy, no need to fail.
Add type hints to adjacent code paths
and necessary refactors.

Fixes GH-5577

---------

Co-authored-by: Brett Holman <brett.holman@canonical.com>
TheRealFalcon added a commit to TheRealFalcon/cloud-init that referenced this pull request Jan 14, 2025
If the server is busy, no need to fail.
Add type hints to adjacent code paths
and necessary refactors.

Fixes canonicalGH-5577

---------

Co-authored-by: Brett Holman <brett.holman@canonical.com>
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.

2 participants