Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aws/lambda/pytorch-auto-revert/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ run-local: venv/bin/python

.PHONY: run-local-workflows
run-local-workflows: venv/bin/python
venv/bin/python -m pytorch_auto_revert workflows pull.yml
venv/bin/python -m pytorch_auto_revert autorevert-checker Lint trunk pull inductor linux-binary-manywheel --hours 4320 --ignore-common-errors

deployment.zip:
mkdir -p deployment
Expand Down
23 changes: 21 additions & 2 deletions aws/lambda/pytorch-auto-revert/pytorch_auto_revert/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ def get_opts() -> argparse.Namespace:
action="store_true",
help="Show what would be restarted without actually doing it (use with --do-restart)",
)
workflow_parser.add_argument(
"--ignore-common-errors",
action="store_true",
help="Ignore common errors in autorevert patterns (e.g., 'No tests found')",
)

# workflow-restart-checker subcommand
workflow_restart_parser = subparsers.add_parser(
Expand Down Expand Up @@ -159,15 +164,29 @@ def main(*args, **kwargs) -> None:
"ClickHouse connection test failed. Please check your configuration."
)

if opts.subcommand == "lambda":
print("TODO: run lambda flow")
if opts.subcommand is None:
autorevert_checker(
[
"Lint",
"trunk",
"pull",
"inductor",
"linux-binary-manywheel",
],
hours=2,
verbose=True,
do_restart=True,
dry_run=False,
ignore_common_errors=True,
)
elif opts.subcommand == "autorevert-checker":
autorevert_checker(
opts.workflows,
hours=opts.hours,
verbose=opts.verbose,
do_restart=opts.do_restart,
dry_run=opts.dry_run,
ignore_common_errors=opts.ignore_common_errors,
)
elif opts.subcommand == "workflow-restart-checker":
workflow_restart_checker(opts.workflow, commit=opts.commit, days=opts.days)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,20 @@ def get_job_base_names(self) -> Set[str]:
class AutorevertPatternChecker:
"""Detects autorevert patterns in workflow job failures."""

def __init__(self, workflow_names: List[str] = None, lookback_hours: int = 48):
def __init__(
self,
workflow_names: List[str] = None,
lookback_hours: int = 48,
ignore_classication_rules: Set[str] = None,
):
self.workflow_names = workflow_names or []
self.lookback_hours = lookback_hours
self._workflow_commits_cache: Dict[str, List[CommitJobs]] = {}
self._commit_history = None
self._ignore_classification_rules = ignore_classication_rules or set()
Comment thread
izaitsevfb marked this conversation as resolved.
Outdated
Comment thread
izaitsevfb marked this conversation as resolved.
Outdated

def get_workflow_commits(self, workflow_name: str) -> List[CommitJobs]:
"""Get workflow commits for a specific workflow, fetching if needed."""
"""Get workflow commits for a specific workflow, fetching if needed. From newer to older"""
if workflow_name not in self._workflow_commits_cache:
self._fetch_workflow_data()
return self._workflow_commits_cache.get(workflow_name, [])
Expand All @@ -90,7 +96,7 @@ def commit_history(self) -> List[Dict]:
return self._commit_history or []

def _fetch_workflow_data(self):
"""Fetch workflow job data from ClickHouse for all workflows in batch."""
"""Fetch workflow job data from ClickHouse for all workflows in batch. From newer to older"""
if not self.workflow_names:
return

Expand Down Expand Up @@ -217,11 +223,11 @@ def _find_last_commit_with_job(
for job in commit.jobs:
if job.name.split("(")[0] == job_name: # Normalize job name
job_results.append(job)
if job_results:
return (
commit,
job_results,
)
if job_results:
return (
commit,
job_results,
)
return None, None

def detect_autorevert_pattern_workflow(self, workflow_name: str) -> List[Dict]:
Expand Down Expand Up @@ -266,6 +272,10 @@ def detect_autorevert_pattern_workflow(self, workflow_name: str) -> List[Dict]:
suspected_failure_class_rule,
suspected_failure_job_name,
) in suspected_failures:
if suspected_failure_class_rule in self._ignore_classification_rules:
# Skip ignored classification rules
continue

newer_commit_same_job, newer_same_jobs = (
self._find_last_commit_with_job(
(commits[j] for j in range(i - 1, -1, -1)),
Expand Down Expand Up @@ -304,18 +314,11 @@ def detect_autorevert_pattern_workflow(self, workflow_name: str) -> List[Dict]:
# No older commit with the same job found
continue

if any(
j.name.split("(")[0] != job_name
for j in last_commit_with_same_job.failed_jobs
):
# newr commit has the same job failing
continue

if any(
j.classification_rule == suspected_failure_class_rule
for j in last_same_jobs
):
# The last commit with the same job has the same failure classification
# The older commit has the same job failing with same rule
continue

patterns.append(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@ def autorevert_checker(
verbose: bool = False,
do_restart: bool = False,
dry_run: bool = False,
ignore_common_errors=True,
):
common_errors = {
"GHA error",
"GHA timeout",
"sccache error",
}

# Initialize checker
checker = AutorevertPatternChecker(workflow_names, hours)
checker = AutorevertPatternChecker(
workflow_names,
hours,
ignore_classication_rules=common_errors if ignore_common_errors else set(),
Comment thread
izaitsevfb marked this conversation as resolved.
Outdated
)

# Fetch data
if verbose:
Expand Down Expand Up @@ -108,7 +119,7 @@ def autorevert_checker(
"category", "uncategorized"
)
print(
f"✓ REVERTED ({category}): {second_commit[:8]} was reverted by {revert_result['revert_sha'][:8]} "
f"✓ REVERTED ({category}): {second_commit} was reverted by {revert_result['revert_sha'][:8]} "
f"after {revert_result['hours_after_target']:.1f} hours"
)
reverted_patterns.append(pattern)
Expand Down