# How to Build Commitment Optimization Author: [nawazdhandala](https://github.com/nawazdhandala) Tags: Cloud, Cost Optimization, FinOps, Reserved Instances Description: Learn how to optimize reserved capacity and savings plan commitments to reduce cloud costs by 30-70% while maintaining flexibility and avoiding costly mistakes. --- Cloud providers offer significant discounts for committing to usage upfront. Reserved Instances (RIs), Savings Plans, and Committed Use Discounts can slash your compute bill by 30-70%. But commit too much and you waste money on unused capacity. Commit too little and you leave savings on the table. Building a commitment optimization strategy requires understanding your usage patterns, choosing the right commitment types, and continuously rebalancing your portfolio. ## Commitment Types Overview Every major cloud provider offers discount mechanisms that trade flexibility for savings. Understanding the differences is crucial before committing a single dollar. ```mermaid flowchart TD subgraph AWS["AWS Commitment Options"] A1[Standard RIs
Up to 72% off
Least flexible] A2[Convertible RIs
Up to 66% off
Can exchange] A3[Compute Savings Plans
Up to 66% off
Most flexible] A4[EC2 Savings Plans
Up to 72% off
Instance family locked] end subgraph GCP["GCP Commitment Options"] G1[Committed Use Discounts
Up to 57% off
Resource-based] G2[Flexible CUDs
Up to 46% off
Spend-based] end subgraph Azure["Azure Commitment Options"] Z1[Reserved Instances
Up to 72% off
VM size locked] Z2[Azure Savings Plans
Up to 65% off
Compute flexible] end ``` ### AWS Commitment Types | Type | Discount | Flexibility | Best For | |------|----------|-------------|----------| | Standard RIs | Up to 72% | Low - locked to instance type, AZ, OS | Stable, predictable workloads | | Convertible RIs | Up to 66% | Medium - can exchange for different attributes | Evolving workloads | | Compute Savings Plans | Up to 66% | High - any instance family, size, region, OS | Dynamic environments | | EC2 Savings Plans | Up to 72% | Medium - locked to instance family in region | Known instance families | ### GCP Commitment Types | Type | Discount | Flexibility | Best For | |------|----------|-------------|----------| | Resource-based CUDs | Up to 57% | Low - specific vCPU and memory amounts | Stable compute needs | | Flexible CUDs | Up to 46% | High - applies to any compute | Variable workloads | ### Azure Commitment Types | Type | Discount | Flexibility | Best For | |------|----------|-------------|----------| | Reserved Instances | Up to 72% | Low - VM size and region locked | Consistent VM sizes | | Azure Savings Plans | Up to 65% | High - any compute service | Mixed compute usage | ## Usage Analysis for Commitment Before purchasing any commitment, you need a clear picture of your baseline usage. The goal is to identify the **stable floor** of usage that runs consistently, which is ideal for commitments. ### Step 1: Export Usage Data ```python import boto3 import pandas as pd from datetime import datetime, timedelta def get_ec2_usage_history(days=90, granularity='DAILY'): """ Extract EC2 usage patterns from AWS Cost Explorer. Returns normalized usage per hour by instance family. Use DAILY for 90-day lookbacks; Cost Explorer hourly granularity is hosted for the past 14 days. """ if granularity == 'HOURLY' and days > 14: raise ValueError( 'Cost Explorer hourly granularity is available for the past 14 days. ' 'Use DAILY for longer lookbacks.' ) client = boto3.client('ce') end_date = datetime.now() start_date = end_date - timedelta(days=days) request = { 'TimePeriod': { 'Start': start_date.strftime('%Y-%m-%d'), 'End': end_date.strftime('%Y-%m-%d') }, 'Granularity': granularity, 'Metrics': ['NormalizedUsageAmount'], 'GroupBy': [ {'Type': 'DIMENSION', 'Key': 'INSTANCE_TYPE_FAMILY'}, {'Type': 'DIMENSION', 'Key': 'REGION'} ], 'Filter': { 'Dimensions': { 'Key': 'SERVICE', 'Values': ['Amazon Elastic Compute Cloud - Compute'] } } } # Parse response into DataFrame records = [] while True: response = client.get_cost_and_usage(**request) period_hours = 1 if granularity == 'HOURLY' else 24 for result in response['ResultsByTime']: timestamp = result['TimePeriod']['Start'] for group in result['Groups']: normalized_amount = float( group['Metrics']['NormalizedUsageAmount']['Amount'] ) records.append({ 'timestamp': timestamp, 'instance_family': group['Keys'][0], 'region': group['Keys'][1], 'normalized_hours': normalized_amount / period_hours }) if 'NextPageToken' not in response: break request['NextPageToken'] = response['NextPageToken'] return pd.DataFrame(records) def calculate_baseline_usage(df, percentile=10): """ Calculate the stable baseline usage floor. Uses the 10th percentile to find consistently running capacity. """ baseline = df.groupby(['instance_family', 'region']).agg({ 'normalized_hours': [ ('p10', lambda x: x.quantile(0.10)), # Baseline floor ('p50', lambda x: x.quantile(0.50)), # Median ('p90', lambda x: x.quantile(0.90)), # Peak ('mean', 'mean'), ('std', 'std') ] }).round(2) baseline.columns = ['baseline', 'median', 'peak', 'mean', 'std_dev'] baseline['variability'] = (baseline['std_dev'] / baseline['mean']).round(2) return baseline.reset_index() ``` ### Step 2: Identify Commitment Candidates ```python def identify_commitment_candidates(baseline_df, min_baseline_hours=1): """ Filter for workloads suitable for commitments. Criteria: - Minimum baseline usage (1 normalized unit/hour = roughly one normalized unit running continuously) - Low variability (coefficient of variation < 0.3) - Consistent presence across the analysis period """ candidates = baseline_df[ (baseline_df['baseline'] >= min_baseline_hours) & (baseline_df['variability'] < 0.3) ].copy() # Calculate potential savings # Assuming 40% average savings from commitments candidates['monthly_on_demand_cost'] = candidates['mean'] * 730 * 0.10 # Example hourly rate candidates['potential_monthly_savings'] = candidates['monthly_on_demand_cost'] * 0.40 return candidates.sort_values('potential_monthly_savings', ascending=False) # Example output visualization def plot_usage_patterns(df, instance_family, region): """ Visualize usage patterns to validate commitment decisions. Shows baseline floor, actual usage, and peak capacity. """ import matplotlib.pyplot as plt filtered = df[ (df['instance_family'] == instance_family) & (df['region'] == region) ].sort_values('timestamp') fig, ax = plt.subplots(figsize=(14, 6)) ax.fill_between(filtered['timestamp'], filtered['normalized_hours'], alpha=0.3, label='Actual Usage') baseline = filtered['normalized_hours'].quantile(0.10) ax.axhline(y=baseline, color='green', linestyle='--', label=f'Baseline (P10): {baseline:.0f}') ax.axhline(y=filtered['normalized_hours'].quantile(0.90), color='red', linestyle='--', label=f'Peak (P90): {filtered["normalized_hours"].quantile(0.90):.0f}') ax.set_xlabel('Date') ax.set_ylabel('Normalized Hours') ax.set_title(f'Usage Pattern: {instance_family} in {region}') ax.legend() return fig ``` ### Usage Analysis Decision Flow ```mermaid flowchart TD A[Collect 90+ days of usage data] --> B[Calculate hourly usage by resource type] B --> C[Compute percentile distributions] C --> D{Variability < 30%?} D -->|Yes| E[Good commitment candidate] D -->|No| F{Can workload be stabilized?} F -->|Yes| G[Implement scheduling/right-sizing first] F -->|No| H[Use on-demand or spot] E --> I[Calculate baseline at P10] I --> J[Size commitment to baseline] G --> A ``` ## Commitment Sizing Strategies The most common mistake in commitment optimization is over-committing. Here are battle-tested strategies for sizing commitments correctly. ### Strategy 1: Conservative Baseline Approach Commit to your 10th percentile usage. This guarantees you will use every committed hour while leaving room for optimization. ```python def calculate_conservative_commitment(usage_df, safety_margin=0.10): """ Calculate commitment size using conservative baseline approach. Args: usage_df: DataFrame with hourly usage data safety_margin: Additional buffer below P10 (default 10%) Returns: Recommended commitment in normalized hours per hour """ # Calculate P10 baseline p10_baseline = usage_df['normalized_hours'].quantile(0.10) # Apply safety margin recommended_commitment = p10_baseline * (1 - safety_margin) # Calculate coverage and savings total_usage = usage_df['normalized_hours'].sum() committed_usage = usage_df['normalized_hours'].clip(upper=recommended_commitment).sum() coverage_rate = committed_usage / total_usage return { 'recommended_hourly_commitment': round(recommended_commitment, 2), 'coverage_rate': round(coverage_rate * 100, 1), 'committed_hours': round(committed_usage, 0), 'on_demand_hours': round(total_usage - committed_usage, 0) } ``` ### Strategy 2: Layered Commitment Approach Build a portfolio with multiple commitment layers that expire at different times. This provides flexibility while maximizing savings. ```mermaid graph TD subgraph "Layered Commitment Portfolio" L1[Layer 1: 3-year commitments
40% of baseline
Highest discount] L2[Layer 2: 1-year commitments
30% of baseline
Medium discount] L3[Layer 3: On-demand
Variable usage
Full flexibility] end L1 --> |"Covers stable floor"| U[Total Usage] L2 --> |"Covers predictable growth"| U L3 --> |"Covers peaks and experiments"| U ``` ```python def design_layered_portfolio(usage_df, growth_rate=0.15): """ Design a multi-layer commitment portfolio. Layer 1 (3-year): Most stable 40% of baseline - highest savings Layer 2 (1-year): Next 30% of baseline - medium savings Layer 3 (On-demand): Remaining variable usage - full flexibility """ baseline = usage_df['normalized_hours'].quantile(0.10) median = usage_df['normalized_hours'].quantile(0.50) # Account for expected growth adjusted_baseline = baseline * (1 + growth_rate) portfolio = { 'layer_1_3year': { 'commitment': round(baseline * 0.40, 2), 'discount': 0.60, # 60% off on-demand 'term_months': 36, 'risk': 'Low - covers absolute minimum usage' }, 'layer_2_1year': { 'commitment': round(baseline * 0.30, 2), 'discount': 0.40, # 40% off on-demand 'term_months': 12, 'risk': 'Medium - covers stable baseline' }, 'layer_3_ondemand': { 'estimated_usage': round(median - (baseline * 0.70), 2), 'discount': 0, 'term_months': 0, 'risk': 'None - pay as you go' } } # Calculate blended savings total_committed = portfolio['layer_1_3year']['commitment'] + \ portfolio['layer_2_1year']['commitment'] weighted_discount = ( (portfolio['layer_1_3year']['commitment'] * 0.60) + (portfolio['layer_2_1year']['commitment'] * 0.40) ) / total_committed portfolio['blended_discount'] = round(weighted_discount * 100, 1) portfolio['total_committed_hours'] = total_committed return portfolio ``` ### Strategy 3: Rolling Purchase Strategy Instead of buying all commitments at once, spread purchases over time to reduce timing risk and maintain flexibility. ```python from datetime import datetime, timedelta def generate_rolling_purchase_schedule( target_commitment: float, months_to_full_coverage: int = 6, commitment_term_months: int = 12 ): """ Generate a rolling purchase schedule to reach target commitment. Benefits: - Reduces timing risk (market changes, usage evolution) - Spreads cash outflow - Creates staggered expiration dates for flexibility """ monthly_increment = target_commitment / months_to_full_coverage schedule = [] current_date = datetime.now() for month in range(months_to_full_coverage): purchase_date = current_date + timedelta(days=30 * month) expiration_date = purchase_date + timedelta(days=30 * commitment_term_months) schedule.append({ 'purchase_date': purchase_date.strftime('%Y-%m-%d'), 'amount': round(monthly_increment, 2), 'cumulative_commitment': round(monthly_increment * (month + 1), 2), 'expiration_date': expiration_date.strftime('%Y-%m-%d'), 'coverage_percentage': round((month + 1) / months_to_full_coverage * 100, 1) }) return schedule # Example usage schedule = generate_rolling_purchase_schedule( target_commitment=100, # 100 normalized hours/hour months_to_full_coverage=6, commitment_term_months=12 ) # Output: # Month 1: Purchase 16.67 hours, 16.7% coverage # Month 2: Purchase 16.67 hours, 33.3% coverage # Month 3: Purchase 16.67 hours, 50.0% coverage # Month 4: Purchase 16.67 hours, 66.7% coverage # Month 5: Purchase 16.67 hours, 83.3% coverage # Month 6: Purchase 16.67 hours, 100.0% coverage ``` ## Term Length Decisions Choosing between 1-year and 3-year terms involves balancing savings against risk. Here is a framework for making this decision. ```mermaid flowchart TD A[Evaluate Workload] --> B{Workload lifespan > 3 years?} B -->|Yes| C{Technology stable?} B -->|No| D[Choose 1-year term] C -->|Yes| E{Cash flow allows upfront?} C -->|No| D E -->|Yes| F[Choose 3-year all upfront] E -->|No| G{Monthly payments acceptable?} G -->|Yes| H[Choose 3-year no upfront] G -->|No| I[Choose 1-year partial upfront] ``` ### Term Length Decision Matrix ```python def recommend_term_length( workload_expected_lifespan_years: float, technology_stability_score: float, # 0-1, 1 = very stable organization_growth_rate: float, # Annual growth rate cash_availability: str # 'high', 'medium', 'low' ) -> dict: """ Recommend commitment term length based on workload characteristics. Returns recommendation with rationale. """ # Risk factors lifespan_risk = 1 if workload_expected_lifespan_years < 2 else 0 tech_risk = 1 if technology_stability_score < 0.7 else 0 growth_risk = 1 if organization_growth_rate > 0.30 else 0 total_risk = lifespan_risk + tech_risk + growth_risk if total_risk >= 2: term = '1-year' rationale = [ 'High uncertainty in workload longevity or technology', 'Recommend shorter term for flexibility', 'Re-evaluate commitment strategy annually' ] elif total_risk == 1: term = 'mixed' rationale = [ 'Moderate risk profile', 'Consider 3-year for stable baseline (40%)', '1-year for remaining commitment (60%)', 'Review quarterly' ] else: term = '3-year' rationale = [ 'Low risk profile - stable workload and technology', 'Maximize savings with 3-year term', 'Consider all-upfront if cash available' ] # Payment recommendation if cash_availability == 'high' and term in ['3-year', 'mixed']: payment = 'all-upfront' additional_savings = '5-10% additional discount' elif cash_availability == 'medium': payment = 'partial-upfront' additional_savings = '2-5% additional discount' else: payment = 'no-upfront' additional_savings = 'Preserves cash flow' return { 'recommended_term': term, 'recommended_payment': payment, 'additional_savings': additional_savings, 'rationale': rationale, 'risk_score': total_risk } ``` ### Break-Even Analysis ```python def calculate_break_even( monthly_on_demand_cost: float, commitment_discount: float, upfront_payment: float, term_months: int ) -> dict: """ Calculate break-even point for a commitment purchase. Args: monthly_on_demand_cost: What you would pay monthly without commitment commitment_discount: Discount percentage (e.g., 0.40 for 40% off) upfront_payment: Any upfront payment required term_months: Length of commitment in months Returns: Break-even analysis including months to break even """ monthly_committed_cost = monthly_on_demand_cost * (1 - commitment_discount) monthly_savings = monthly_on_demand_cost - monthly_committed_cost # Account for upfront payment if upfront_payment > 0: months_to_break_even = upfront_payment / monthly_savings else: months_to_break_even = 0 # Immediate savings total_savings = (monthly_savings * term_months) - upfront_payment roi = total_savings / (upfront_payment if upfront_payment > 0 else monthly_committed_cost * term_months) return { 'months_to_break_even': round(months_to_break_even, 1), 'monthly_savings': round(monthly_savings, 2), 'total_term_savings': round(total_savings, 2), 'roi_percentage': round(roi * 100, 1), 'risk_window_months': round(months_to_break_even, 0), 'safe_after_month': int(months_to_break_even) + 1 } # Example: Compare 1-year vs 3-year one_year = calculate_break_even( monthly_on_demand_cost=10000, commitment_discount=0.40, upfront_payment=0, term_months=12 ) three_year = calculate_break_even( monthly_on_demand_cost=10000, commitment_discount=0.60, upfront_payment=72000, # 2 years upfront term_months=36 ) # 1-year: Immediate break-even, $48,000 total savings, lower risk # 3-year: 12 month break-even, $144,000 total savings, higher initial risk ``` ## Payment Option Analysis Each payment option offers different trade-offs between cash flow and savings. ### AWS Payment Options Comparison | Payment Option | Upfront Cost | Effective Discount | Cash Flow Impact | Best For | |---------------|--------------|-------------------|------------------|----------| | All Upfront | 100% | Highest (up to 72%) | High initial outlay | Cash-rich organizations | | Partial Upfront | ~50% | Medium (up to 66%) | Moderate | Balanced approach | | No Upfront | 0% | Lowest (up to 40%) | Predictable monthly | Cash-constrained orgs | ```python def compare_payment_options( monthly_on_demand_cost: float, term_years: int = 1 ) -> pd.DataFrame: """ Compare all payment options for a given commitment. AWS EC2 Savings Plan discount approximations: - 1-year: All Upfront 40%, Partial 38%, No Upfront 36% - 3-year: All Upfront 60%, Partial 56%, No Upfront 52% """ if term_years == 1: options = { 'all_upfront': {'discount': 0.40, 'upfront_pct': 1.0}, 'partial_upfront': {'discount': 0.38, 'upfront_pct': 0.5}, 'no_upfront': {'discount': 0.36, 'upfront_pct': 0.0} } else: # 3-year options = { 'all_upfront': {'discount': 0.60, 'upfront_pct': 1.0}, 'partial_upfront': {'discount': 0.56, 'upfront_pct': 0.5}, 'no_upfront': {'discount': 0.52, 'upfront_pct': 0.0} } term_months = term_years * 12 total_on_demand = monthly_on_demand_cost * term_months results = [] for option, params in options.items(): discounted_total = total_on_demand * (1 - params['discount']) upfront = discounted_total * params['upfront_pct'] monthly = (discounted_total - upfront) / term_months if params['upfront_pct'] < 1 else 0 results.append({ 'option': option, 'discount_pct': params['discount'] * 100, 'upfront_payment': round(upfront, 2), 'monthly_payment': round(monthly, 2), 'total_cost': round(discounted_total, 2), 'total_savings': round(total_on_demand - discounted_total, 2), 'npv_at_5pct': round(calculate_npv(upfront, monthly, term_months, 0.05), 2) }) return pd.DataFrame(results) def calculate_npv(upfront: float, monthly: float, months: int, annual_rate: float) -> float: """Calculate Net Present Value of payment stream.""" monthly_rate = annual_rate / 12 npv = upfront for month in range(1, months + 1): npv += monthly / ((1 + monthly_rate) ** month) return npv ``` ### Payment Decision Framework ```mermaid flowchart TD A[Evaluate Financial Position] --> B{Weighted Average Cost of Capital?} B -->|WACC < 5%| C[All Upfront maximizes savings] B -->|WACC 5-10%| D[Partial Upfront balances savings and cash] B -->|WACC > 10%| E[No Upfront preserves capital for higher returns] C --> F{Cash reserves > 6 months OpEx?} F -->|Yes| G[Proceed with All Upfront] F -->|No| H[Consider Partial Upfront] D --> I[Default recommendation for most orgs] E --> J[Invest capital elsewhere, pay monthly] ``` ## Commitment Portfolio Management Managing commitments is not a one-time activity. You need continuous monitoring and rebalancing. ### Portfolio Dashboard Metrics ```python class CommitmentPortfolioManager: """ Manage and monitor cloud commitment portfolio. """ def __init__(self, commitments: list, usage_data: pd.DataFrame): self.commitments = commitments self.usage = usage_data def calculate_utilization(self) -> dict: """ Calculate commitment utilization rate. Target: > 95% utilization to avoid waste. """ total_committed = sum(c['hourly_commitment'] for c in self.commitments) total_used = self.usage['normalized_hours'].mean() utilization = min(total_used / total_committed, 1.0) if total_committed > 0 else 0 return { 'utilization_rate': round(utilization * 100, 1), 'committed_hours': total_committed, 'used_hours': round(total_used, 2), 'wasted_hours': round(max(0, total_committed - total_used), 2), 'status': 'healthy' if utilization > 0.95 else 'review_needed' } def calculate_coverage(self) -> dict: """ Calculate what percentage of usage is covered by commitments. Target: 70-80% coverage for optimal balance. """ total_committed = sum(c['hourly_commitment'] for c in self.commitments) total_used = self.usage['normalized_hours'].mean() coverage = total_committed / total_used if total_used > 0 else 0 return { 'coverage_rate': round(coverage * 100, 1), 'on_demand_percentage': round((1 - min(coverage, 1)) * 100, 1), 'recommendation': self._coverage_recommendation(coverage) } def _coverage_recommendation(self, coverage: float) -> str: if coverage < 0.60: return 'Under-committed: Consider purchasing additional commitments' elif coverage > 0.90: return 'Over-committed: Risk of waste, reduce future purchases' else: return 'Optimal coverage: Maintain current strategy' def get_expiring_commitments(self, days: int = 90) -> list: """ List commitments expiring within specified days. """ from datetime import datetime, timedelta cutoff = datetime.now() + timedelta(days=days) expiring = [] for c in self.commitments: exp_date = datetime.strptime(c['expiration_date'], '%Y-%m-%d') if exp_date <= cutoff: c['days_until_expiration'] = (exp_date - datetime.now()).days expiring.append(c) return sorted(expiring, key=lambda x: x['days_until_expiration']) def generate_renewal_recommendations(self) -> list: """ Generate recommendations for expiring commitments. """ expiring = self.get_expiring_commitments(days=90) utilization = self.calculate_utilization() recommendations = [] for commitment in expiring: if utilization['utilization_rate'] > 95: action = 'renew' rationale = 'High utilization, commitment is fully used' elif utilization['utilization_rate'] > 80: action = 'renew_reduced' rationale = 'Moderate utilization, consider reducing size by 10-20%' else: action = 'let_expire' rationale = 'Low utilization, let expire and right-size' recommendations.append({ 'commitment_id': commitment.get('id'), 'expiration_date': commitment['expiration_date'], 'current_size': commitment['hourly_commitment'], 'recommended_action': action, 'rationale': rationale }) return recommendations ``` ### Automated Monitoring Alerts ```python def setup_commitment_alerts(portfolio_manager: CommitmentPortfolioManager): """ Define alerting thresholds for commitment portfolio health. Integrate with monitoring tools like OneUptime. """ alerts = { 'low_utilization': { 'condition': lambda pm: pm.calculate_utilization()['utilization_rate'] < 90, 'severity': 'warning', 'message': 'Commitment utilization below 90% - potential waste detected', 'action': 'Review commitment portfolio and usage patterns' }, 'critical_low_utilization': { 'condition': lambda pm: pm.calculate_utilization()['utilization_rate'] < 70, 'severity': 'critical', 'message': 'Commitment utilization critically low - significant waste', 'action': 'Immediately review and consider selling/exchanging commitments' }, 'under_coverage': { 'condition': lambda pm: pm.calculate_coverage()['coverage_rate'] < 50, 'severity': 'info', 'message': 'Coverage below 50% - savings opportunity available', 'action': 'Evaluate purchasing additional commitments' }, 'expiring_soon': { 'condition': lambda pm: len(pm.get_expiring_commitments(days=30)) > 0, 'severity': 'warning', 'message': 'Commitments expiring within 30 days', 'action': 'Review and plan renewal or replacement' } } return alerts # Example integration with monitoring def check_portfolio_health(portfolio_manager): """ Run health checks and return status for monitoring integration. """ alerts = setup_commitment_alerts(portfolio_manager) triggered = [] for alert_name, alert_config in alerts.items(): if alert_config['condition'](portfolio_manager): triggered.append({ 'alert': alert_name, 'severity': alert_config['severity'], 'message': alert_config['message'], 'action': alert_config['action'] }) return { 'status': 'critical' if any(a['severity'] == 'critical' for a in triggered) else 'warning' if triggered else 'healthy', 'triggered_alerts': triggered, 'metrics': { 'utilization': portfolio_manager.calculate_utilization(), 'coverage': portfolio_manager.calculate_coverage(), 'expiring_30d': len(portfolio_manager.get_expiring_commitments(days=30)) } } ``` ### Portfolio Rebalancing Workflow ```mermaid sequenceDiagram participant Scheduler participant Analyzer participant Portfolio participant Alerts participant Finance Scheduler->>Analyzer: Weekly: Analyze usage patterns Analyzer->>Portfolio: Update utilization metrics Portfolio->>Alerts: Check threshold breaches alt Utilization < 90% Alerts->>Finance: Alert: Review commitment waste Finance->>Portfolio: Evaluate exchange/sell options end alt Coverage < 60% Alerts->>Finance: Alert: Savings opportunity Finance->>Analyzer: Request commitment recommendations Analyzer->>Finance: Return sized recommendations end Scheduler->>Portfolio: Monthly: Check expirations Portfolio->>Finance: List commitments expiring in 90 days Finance->>Analyzer: Analyze renewal vs new purchase Analyzer->>Finance: Return renewal recommendations ``` ## Putting It All Together Here is a complete commitment optimization workflow: ```python class CommitmentOptimizer: """ End-to-end commitment optimization workflow. """ def __init__(self, cloud_provider: str = 'aws'): self.provider = cloud_provider self.usage_analyzer = None self.portfolio_manager = None def run_optimization_cycle(self) -> dict: """ Execute full optimization cycle. Run monthly or when significant usage changes detected. """ # Step 1: Collect and analyze usage usage_data = self._collect_usage_data(days=90) baseline = calculate_baseline_usage(usage_data) # Step 2: Identify candidates candidates = identify_commitment_candidates(baseline) # Step 3: Current portfolio health current_health = check_portfolio_health(self.portfolio_manager) # Step 4: Generate recommendations recommendations = self._generate_recommendations( candidates=candidates, current_health=current_health ) # Step 5: Build purchase plan purchase_plan = self._build_purchase_plan(recommendations) return { 'analysis_date': datetime.now().isoformat(), 'usage_summary': { 'total_baseline_hours': baseline['baseline'].sum(), 'candidate_workloads': len(candidates), 'current_coverage': current_health['metrics']['coverage']['coverage_rate'] }, 'portfolio_health': current_health, 'recommendations': recommendations, 'purchase_plan': purchase_plan, 'estimated_annual_savings': self._estimate_savings(purchase_plan) } def _generate_recommendations(self, candidates, current_health): """Generate actionable recommendations based on analysis.""" recommendations = [] # Handle under-coverage if current_health['metrics']['coverage']['coverage_rate'] < 70: for _, candidate in candidates.iterrows(): rec = { 'type': 'new_purchase', 'workload': f"{candidate['instance_family']} in {candidate['region']}", 'recommended_commitment': candidate['baseline'] * 0.8, 'estimated_monthly_savings': candidate['potential_monthly_savings'], 'recommended_term': recommend_term_length( workload_expected_lifespan_years=3, technology_stability_score=0.8, organization_growth_rate=0.15, cash_availability='medium' ) } recommendations.append(rec) # Handle expiring commitments for renewal in self.portfolio_manager.generate_renewal_recommendations(): recommendations.append({ 'type': 'renewal', **renewal }) return recommendations def _build_purchase_plan(self, recommendations): """Convert recommendations into a phased purchase plan.""" new_purchases = [r for r in recommendations if r['type'] == 'new_purchase'] if not new_purchases: return {'purchases': [], 'total_upfront': 0} # Use rolling purchase strategy total_commitment = sum(r['recommended_commitment'] for r in new_purchases) schedule = generate_rolling_purchase_schedule( target_commitment=total_commitment, months_to_full_coverage=6, commitment_term_months=12 ) return { 'strategy': 'rolling_6_month', 'purchases': schedule, 'total_commitment_target': total_commitment } def _estimate_savings(self, purchase_plan): """Estimate annual savings from recommended purchases.""" if not purchase_plan.get('purchases'): return 0 # Assume average 45% discount and $0.10/hour average rate total_hours = purchase_plan['total_commitment_target'] * 8760 # Annual hours on_demand_cost = total_hours * 0.10 committed_cost = on_demand_cost * 0.55 # 45% discount return round(on_demand_cost - committed_cost, 2) ``` ## Key Takeaways 1. **Start with data**: Analyze at least 90 days of usage before purchasing any commitments. The 10th percentile is your safe baseline. 2. **Layer your commitments**: Do not put all your eggs in one basket. Use a mix of 3-year (for stable floor) and 1-year (for flexibility) commitments. 3. **Roll purchases over time**: Spread purchases across 3-6 months to reduce timing risk and create staggered expirations. 4. **Monitor continuously**: Set up alerts for utilization below 90% and coverage below 60%. Review expiring commitments 90 days in advance. 5. **Match payment to cash flow**: All-upfront maximizes savings but ties up capital. Choose based on your organization's weighted average cost of capital. 6. **Automate the workflow**: Manual commitment management does not scale. Build or buy tools to continuously analyze usage and recommend adjustments. Commitment optimization is not a one-time project but an ongoing discipline. The organizations that save the most treat their commitment portfolio like a financial asset: continuously monitored, regularly rebalanced, and aligned with business strategy. ## Further Reading - [AWS Savings Plans User Guide](https://docs.aws.amazon.com/savingsplans/latest/userguide/) - [GCP Committed Use Discounts](https://cloud.google.com/compute/docs/instances/committed-use-discounts-overview) - [Azure Reservations](https://docs.microsoft.com/en-us/azure/cost-management-billing/reservations/) - [FinOps Foundation - Commitment-Based Discounts](https://www.finops.org/framework/capabilities/commitment-based-discounts/)