1+ """
2+ This script starts and monitors AWS Step Function executions, calculates execution statistics,
3+ and outputs the results. It uses the boto3 library to interact with AWS Step Functions.
4+
5+ Usage:
6+ python performance_test.py --profile <AWS_PROFILE> --state-machine-arn <STATE_MACHINE_ARN> --count <NUMBER_OF_EXECUTIONS>
7+
8+ Arguments:
9+ --profile: The AWS CLI profile name to use for authentication.
10+ --state-machine-arn: The ARN of the Step Function state machine to execute.
11+ --count: The number of Step Function executions to submit (default is 1).
12+ """
13+
14+ import pathlib
15+ from os .path import dirname , realpath , basename
16+ import boto3
17+ import datetime
18+ import time
19+ import argparse
20+ import logging
21+ import statistics
22+
23+ # Configure logging
24+ logging .basicConfig (
25+ level = logging .INFO ,
26+ format = "%(asctime)s - %(levelname)s - %(message)s" ,
27+ datefmt = "%Y-%m-%d %H:%M:%S"
28+ )
29+
30+ # Parse command-line arguments
31+ parser = argparse .ArgumentParser (description = "Start and monitor Step Function executions." )
32+ parser .add_argument ("--profile" , required = True , help = "boto3 profile name" )
33+ parser .add_argument ("--state-machine-arn" , required = True , help = "Step Function state machine ARN" )
34+ parser .add_argument ("--count" , type = int , default = 1 , help = "Number of Step Function executions to submit" )
35+ args = parser .parse_args ()
36+
37+ # Create a boto3 session using the specified profile
38+ session = boto3 .Session (profile_name = args .profile )
39+ client = session .client ('stepfunctions' )
40+ now = datetime .datetime .now (tz = datetime .timezone .utc )
41+
42+ # Path to the sample message file
43+ message = pathlib .Path (dirname (realpath (__file__ ))).joinpath ('../tests/sample_messages' ).joinpath (
44+ 'cma.uat.workflow-input.OPERA_L3_DSWx-S1_T45QYD_20241001T121219Z_20241206T065726Z_S1A_30_v1.0.json'
45+ ).read_text ()
46+
47+ # Dictionary to store submission details
48+ submissions : dict [str , dict ] = {}
49+
50+ # Start the specified number of Step Function executions
51+ for i in range (args .count ):
52+ response = client .start_execution (
53+ stateMachineArn = args .state_machine_arn ,
54+ name = f'{ now .strftime ("%Y%m%dT%H%M%S" )} _{ basename (__file__ )} _{ i } ' ,
55+ input = message
56+ )
57+ logging .info (f"Started execution { i } with ARN: { response ['executionArn' ]} " )
58+ submissions [response ['executionArn' ]] = {'i' : i } | response
59+
60+ # Monitor the executions until all are complete
61+ all_complete = False
62+ while not all_complete :
63+ all_complete = True
64+ for executionArn , submission in submissions .items ():
65+ # Check the status of each execution
66+ if 'status' not in submission or submission ['status' ] == 'RUNNING' :
67+ response = client .describe_execution (
68+ executionArn = executionArn
69+ )
70+ submissions [executionArn ].update (response )
71+ if response ['status' ] == 'RUNNING' :
72+ all_complete = False
73+ break
74+ logging .info (f"Execution { submission ['i' ]} is complete with status: { submission ['status' ]} " )
75+ if not all_complete :
76+ logging .info ("Waiting for executions to complete..." )
77+ time .sleep (10 )
78+
79+ # Calculate statistics for execution durations
80+ data = [
81+ (sub ['stopDate' ] - sub ['startDate' ]).total_seconds ()
82+ for sub in submissions .values ()
83+ if 'stopDate' in sub and 'startDate' in sub
84+ ]
85+
86+ # Compute statistical metrics
87+ mean_value = statistics .mean (data )
88+ median_value = statistics .median (data )
89+ try :
90+ mode_value = statistics .mode (data ) # Raises StatisticsError if no unique mode
91+ except statistics .StatisticsError :
92+ mode_value = "No unique mode"
93+ stdev_value = statistics .stdev (data )
94+ variance_value = statistics .variance (data )
95+
96+ # Log the calculated statistics
97+ logging .info (f"Count: { len (data )} " )
98+ logging .info (f"Mean: { mean_value } " )
99+ logging .info (f"Median: { median_value } " )
100+ logging .info (f"Mode: { mode_value } " )
101+ logging .info (f"Standard Deviation: { stdev_value } " )
102+ logging .info (f"Variance: { variance_value } " )
0 commit comments