Untitled

 avatar
unknown
plain_text
a year ago
6.4 kB
21
Indexable
import argparse
import ast
import sys
from datetime import datetime, date  # CHANGE: added `date` for daily retry tracking
import time
import re
import json
from azureml.core import Workspace, Experiment, Run
from azureml.pipeline.core import PipelineRun, StepRun
from azure.ai.ml import MLClient, dsl, load_component
from azure.ai.ml.entities import Job
from azure.identity import DefaultAzureCredential, InteractiveBrowserCredential, ManagedIdentityCredential

# CHANGE: Introduce global retry tracking variables
RETRY_TRACKER = {"count": 0, "day": date.today()}
MAX_RETRIES_PER_DAY = 10  # CHANGE: configurable retry limit


def create_aml_client(config_path: str = "config.json") -> MLClient:
    """
    initialize AML client based on credentials
    """
    with open(config_path) as json_file:
        data = json.load(json_file)
    print(data)
    credential = DefaultAzureCredential()
    ml_client = MLClient.from_config(credential=credential, path=config_path)
    return ml_client


def parse_args() -> argparse.Namespace:
    """
    command line parser
    """
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "--experiment-name",
        type=str,
        default="One sentence summary billing",
        help="Name of the experiment",
    )
    parser.add_argument(
        "--schedule-name",
        type=str,
        help="Name of the schedule",
    )
    parser.add_argument(
        "--components-monitor-list",
        type=str,
        help="list of components to be monitored",
    )
    parser.add_argument(
        "--max-retries-per-day",  # CHANGE: allow overriding retry limit via CLI
        type=int,
        default=10,
        help="Maximum number of retries allowed per day",
    )
    return parser.parse_args()


# CHANGE: Helper function to check retry quota
def can_retry(max_retries: int) -> bool:
    global RETRY_TRACKER
    today = date.today()

    # Reset counter if a new day starts
    if RETRY_TRACKER["day"] != today:
        RETRY_TRACKER["count"] = 0
        RETRY_TRACKER["day"] = today

    if RETRY_TRACKER["count"] < max_retries:
        RETRY_TRACKER["count"] += 1
        print(f"[Retry Tracker] Retry attempt {RETRY_TRACKER['count']} of {max_retries} for {today}")
        return True
    else:
        print(f"[Retry Tracker] Daily retry limit ({max_retries}) reached for {today}. No more retries.")
        return False


def mointor_components_sdk_v2(experiment_name, components_monitor_list, schedule_name, max_retries):
    ml_client = create_aml_client()
    components_monitor_list = ast.literal_eval(components_monitor_list.replace("\\", ""))
    print(components_monitor_list)
    time.sleep(5)
    ws = Run.get_context().experiment.workspace

    # Get the experiment
    experiment = Experiment(workspace=ws, name=experiment_name)
    runs = experiment.get_runs()
    for index, run in enumerate(runs):
        if index == 0:
            print(f"Run ID: {run.id}, Status: {run.status} ,{run.display_name}")
            job_id = run.id
        break

    start_time = time.time()
    completed_count = 0
    while len(components_monitor_list) > completed_count:
        step_status_list = []
        print(job_id)
        job_status = ml_client.jobs.get(job_id).status
        print(f"jobs_name:{run.id}")

        components = ml_client.jobs.list(parent_job_name=run.id)

        for component in components:
            print(
                f"component Name & ID: {component.display_name},{component.name}, "
                f"Status: {component.status}: Created at :{component.creation_context.created_at}"
            )
            dt = datetime.fromisoformat(str(component.creation_context.created_at))
            epoch_time = dt.timestamp()
            tup = (component.display_name, component.status, epoch_time)
            step_status_list.append(tup)
            print(step_status_list)

        completed_count = 0
        for step_name, step_status, step_start_time in step_status_list:
            if step_status == "Completed":
                completed_count += 1
                print(f"completed_count:{completed_count}")
            elapsed_time = time.time() - step_start_time
            for component_name, threshold_duration in components_monitor_list:
                if component_name == step_name and step_status == "Running" and elapsed_time > threshold_duration:
                    print(f"{component_name} running for more than {threshold_duration} secs. Cancelling...")

                    # CHANGE: check retry quota before triggering
                    if can_retry(max_retries):
                        print(f"Triggering {schedule_name} schedule")
                        ml_client.schedules.trigger(schedule_name)
                    else:
                        print("Retry skipped due to daily cap.")

                    print("Cancelling Job....")
                    cancel = ml_client.jobs.begin_cancel(run.id)
                    print(cancel.status())
                    sys.exit()

                elif component_name == step_name and step_status == "Completed":
                    print(f"{component_name} completed successfully.")

                elif component_name == step_name and step_status == "Failed":
                    print(f"{component_name} failed, Retriggering the schedule in 15 mins...")

                    # CHANGE: check retry quota before triggering
                    if can_retry(max_retries):
                        time.sleep(900)
                        print(f"Triggering {schedule_name} schedule")
                        ml_client.schedules.trigger(schedule_name)
                    else:
                        print("Retry skipped due to daily cap.")

                    print("Cancelling Job....")
                    cancel = ml_client.jobs.begin_cancel(run.id)
                    print(cancel.status())
                    sys.exit()
        time.sleep(10)
    return True


if __name__ == "__main__":
    args = parse_args()

    # CHANGE: pass retry limit from CLI args
    mointor_components_sdk_v2(
        args.experiment_name,
        args.components_monitor_list,
        args.schedule_name,
        args.max_retries_per_day,
    )
Editor is loading...
Leave a Comment