
Adaptive Adjustment of AWS RI Purchase Targets: A Sigmoid-Based Approach
Introduction
At Harness, we help our customers maximize cloud savings by automating the purchase of AWS Reserved Instances (RIs).
An important part of this process is ensuring we buy the right amount of commitment — enough to capture significant savings, but not so much that it leads to wastage.
While our forecasting models accurately predict future usage, we noticed an issue: our actual purchasing behavior was too abrupt.
As we approached our target reservation coverage, the system would either buy too aggressively or stop too suddenly, leading to suboptimal results.
We needed a better way to smoothly adjust the target purchase cost as we got closer to our goals.
This blog explains how we solved this using a sigmoid function, why we chose it over other approaches, and how it fits into our overall forecasting and purchasing system.
Our Forecasting and Purchasing Pipeline
Here’s a quick overview of how we make purchase recommendations:
- Collect Historical Data:
We pull detailed compute usage history directly from customers’ AWS accounts — focused primarily on EC2. - Forecast Future Usage:
We send this data to our Forecasting Engine, which uses time series modeling to predict future compute demand. - Target Coverage Setup:
As part of initial onboarding, customers configure their desired target reservation coverage — for example, 70% or 80% — based on their risk appetite and cost savings goals. - Generate Target Purchases:
Based on the forecasted usage and the customer’s configured target coverage, the system calculates a target reservation cost — essentially, how much commitment we should purchase. - Adjust Target Cost Dynamically:
Before placing a reservation order, we pass the forecasted target through the cost adjustment function described in this blog to fine-tune the purchase amount based on real-time progress toward target coverage. - Recommend and/or Auto-Purchase:
Finally, the system recommends purchases to customers or automatically buys, depending on their configuration.
The Challenge
Our early approach simply compared current coverage to target coverage.
If coverage was below target, we kept buying; if it was at or above target, we stopped.
Problem:
- When close to the target, small fluctuations in usage would cause wild swings in purchase behavior.
- We either over-purchased or under-purchased, leading to unnecessary cost or missed savings.
- The transition between purchasing and stopping was too sharp and unpredictable.
We needed a way to:
- Start reducing purchase targets before hitting 100% coverage
- Gradually taper down purchasing as we approached target
- Maintain smooth, controlled behavior
Early Alternatives We Explored
Before arriving at the sigmoid solution, we explored several approaches

In the end, the sigmoid function provided the smoothest, most tunable, and most natural progression.
The Solution: Sigmoid-Based Adjustment
We implemented an adjustment function based on the classic sigmoid formula:

Where:
xis the progress ratio (current coverage/target coverage)x₀shifts the center of the curve (we chose 0.5)kcontrols how steep the transition is (we chose 4.0)
This allows us to:
- Keep purchasing aggressively when coverage is low
- Begin reducing cost gently after reaching ~50% of the target
- Ramp down sharply as we get very close to the target
- Fully stop once we hit or exceed the configured target coverage
go
func
/* Syntax highlighting for code blocks */ .hljs-keyword { color: #569cd6; font-weight: bold; } .hljs-string { color: #ce9178; } .hljs-number { color: #b5cea8; } .hljs-comment { color: #6a9955; font-style: italic; } .hljs-function { color: #dcdcaa; } .hljs-variable { color: #9cdcfe; } .hljs-type { color: #4ec9b0; } .hljs-built_in { color: #4fc1ff; } .hljs-operator { color: #d4d4d4; } .hljs-punctuation { color: #d4d4d4; } .hljs-attr { color: #92c5f8; } .hljs-property { color: #9cdcfe; } .hljs-title { color: #dcdcaa; } .hljs-class { color: #4ec9b0; } .hljs-meta { color: #569cd6; } .hljs-literal { color: #569cd6; } .hljs-symbol { color: #ce9178; } .hljs-regexp { color: #d16969; } .hljs-link { color: #3794ff; text-decoration: underline; } .hljs-selector-tag { color: #569cd6; } .hljs-selector-id { color: #ffd700; } .hljs-selector-class { color: #d7ba7d; } .hljs-addition { color: #4fc1ff; background-color: rgba(79, 193, 255, 0.1); } .hljs-deletion { color: #f85149; background-color: rgba(248, 81, 73, 0.1); }
Tuning the Constants
We tuned three main constants to balance smoothness and control:
csharp
const
/* Syntax highlighting for code blocks */ .hljs-keyword { color: #569cd6; font-weight: bold; } .hljs-string { color: #ce9178; } .hljs-number { color: #b5cea8; } .hljs-comment { color: #6a9955; font-style: italic; } .hljs-function { color: #dcdcaa; } .hljs-variable { color: #9cdcfe; } .hljs-type { color: #4ec9b0; } .hljs-built_in { color: #4fc1ff; } .hljs-operator { color: #d4d4d4; } .hljs-punctuation { color: #d4d4d4; } .hljs-attr { color: #92c5f8; } .hljs-property { color: #9cdcfe; } .hljs-title { color: #dcdcaa; } .hljs-class { color: #4ec9b0; } .hljs-meta { color: #569cd6; } .hljs-literal { color: #569cd6; } .hljs-symbol { color: #ce9178; } .hljs-regexp { color: #d16969; } .hljs-link { color: #3794ff; text-decoration: underline; } .hljs-selector-tag { color: #569cd6; } .hljs-selector-id { color: #ffd700; } .hljs-selector-class { color: #d7ba7d; } .hljs-addition { color: #4fc1ff; background-color: rgba(79, 193, 255, 0.1); } .hljs-deletion { color: #f85149; background-color: rgba(248, 81, 73, 0.1); }

Behavior Visualization
Here’s how the cost adjustment multiplier behaves based on coverage progress:


Edge Cases and Safeguards
Our function safely handles:
- Zero or negative targets → No adjustment applied
- Low progress (< 50%) → No reduction, continue full spend
- Exceeding target coverage (progressRatio ≥ 1) → Stop all purchasing
- Negative adjusted costs → Clamp to 0
This ensures stable, predictable behavior even during volatile usage patterns.
Results and Impact
Since implementing sigmoid-based cost adjustment:
- Cloud savings increased by 5–10% across test accounts
- Overspending reduced
- Purchasing behavior became much smoother and more predictable
Future Work
We are exploring:
- Dynamic smoothing factors based on workload volatility
- Alternative smooth curves (e.g., softplus) for even finer control
- Customer-specific tuning based on risk appetite
Conclusion
Even small mathematical refinements — like introducing a sigmoid decay in purchasing behavior — can make a big difference in cloud cost optimization.
At Harness, we believe that combining robust forecasting with intelligent adjustment mechanisms is the key to maximizing savings, reducing risk, and delighting customers.
