From 8d3ef6e29f3a9ccc906505912acf015d19726191 Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Mon, 10 Oct 2022 16:42:10 -0400 Subject: [PATCH 1/2] Warn on & skip workflow runs for certain "broken" workflows --- src/tinuous/github.py | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/tinuous/github.py b/src/tinuous/github.py index 4b4b66a..d97a531 100644 --- a/src/tinuous/github.py +++ b/src/tinuous/github.py @@ -7,12 +7,13 @@ from github import Github from github.GitRelease import GitRelease from github.GitReleaseAsset import GitReleaseAsset -from github.GithubException import RateLimitExceededException +from github.GithubException import RateLimitExceededException, UnknownObjectException from github.Repository import Repository from github.Workflow import Workflow from github.WorkflowRun import WorkflowRun from pydantic import BaseModel, Field import requests +from urllib3.exceptions import ResponseError from urllib3.util.retry import Retry from .base import ( @@ -98,11 +99,39 @@ def get_workflows(self) -> List[Workflow]: @retry_ratelimit def get_runs(self, wf: Workflow, since: datetime) -> List[WorkflowRun]: runs: List[WorkflowRun] = [] - for r in wf.get_runs(): - if ensure_aware(r.created_at) <= since: - break - runs.append(r) - return runs + try: + for r in wf.get_runs(): + if ensure_aware(r.created_at) <= since: + break + runs.append(r) + return runs + except requests.exceptions.RetryError as e: + reason = e.args[0].reason + if ( + isinstance(reason, ResponseError) + and reason.args[0] + == ResponseError.SPECIFIC_ERROR.format(status_code=500) + and ensure_aware(wf.updated_at) <= since + and not (wf.path and self.has_file(wf.path)) + ): + log.warning( + "Request for runs for workflow %s (%s) returned 500, and" + " workflow was deleted before starting timestamp; skipping", + wf.path, + wf.name, + ) + return [] + else: + raise + + @retry_ratelimit + def has_file(self, path: str) -> bool: + try: + self.ghrepo.get_contents(path) + except UnknownObjectException: + return False + else: + return True def get_build_assets( self, event_types: List[EventType], logs: bool, artifacts: bool From 74066c73397bae0c47f1f1b102ccb55b88cb44bc Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Oct 2022 15:12:25 -0400 Subject: [PATCH 2/2] Also skip on other 5xx errors --- src/tinuous/github.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/tinuous/github.py b/src/tinuous/github.py index d97a531..c832988 100644 --- a/src/tinuous/github.py +++ b/src/tinuous/github.py @@ -35,6 +35,12 @@ sanitize_pathname, ) +RETRY_STATUSES = [500, 502, 503, 504] + +RETRY_RESPONSE_ERRORS = { + ResponseError.SPECIFIC_ERROR.format(status_code=c): c for c in RETRY_STATUSES +} + def retry_ratelimit(func: Callable) -> Callable: @wraps(func) @@ -67,7 +73,7 @@ def client(self) -> Github: retry=Retry( total=12, backoff_factor=1.25, - status_forcelist=[500, 502, 503, 504], + status_forcelist=RETRY_STATUSES, ), ) @@ -109,16 +115,16 @@ def get_runs(self, wf: Workflow, since: datetime) -> List[WorkflowRun]: reason = e.args[0].reason if ( isinstance(reason, ResponseError) - and reason.args[0] - == ResponseError.SPECIFIC_ERROR.format(status_code=500) + and reason.args[0] in RETRY_RESPONSE_ERRORS and ensure_aware(wf.updated_at) <= since and not (wf.path and self.has_file(wf.path)) ): log.warning( - "Request for runs for workflow %s (%s) returned 500, and" + "Request for runs for workflow %s (%s) returned %d, and" " workflow was deleted before starting timestamp; skipping", wf.path, wf.name, + RETRY_RESPONSE_ERRORS[reason.args[0]], ) return [] else: