Skip to content

Commit 6efd528

Browse files
authored
chore: switch metrics & elasticache calls to manual pagination (#332)
Manually paginate the metrics and elasticache/serverless elasticache calls, since the rate limiting code does not work properly with the paginator stream AWS client code.
1 parent 98aeb6c commit 6efd528

File tree

3 files changed

+69
-84
lines changed

3 files changed

+69
-84
lines changed

momento/src/commands/cloud_linter/elasticache.rs

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -217,45 +217,38 @@ async fn describe_clusters(
217217
control_plane_limiter: Arc<DefaultDirectRateLimiter>,
218218
region: &str,
219219
) -> Result<Vec<ElastiCacheResource>, CliError> {
220-
let mut resources = Vec::new();
221-
let mut elasticache_stream = elasticache_client
222-
.describe_cache_clusters()
223-
.show_cache_node_info(true)
224-
.into_paginator()
225-
.send();
226-
227-
while let Some(result) = rate_limit(Arc::clone(&control_plane_limiter), || {
228-
elasticache_stream.next()
229-
})
230-
.await
231-
{
232-
match result {
233-
Ok(result) => {
234-
if let Some(aws_clusters) = result.cache_clusters {
235-
let mut chunks = Vec::new();
236-
for chunk in aws_clusters.chunks(10) {
237-
chunks.push(chunk.to_owned());
238-
}
239-
for clusters in chunks {
240-
for cluster in clusters {
241-
let cluster_resources = convert_to_resources(cluster, region).await?;
242-
resources.extend(cluster_resources);
243-
}
244-
}
245-
}
246-
}
247-
Err(err) => {
248-
return Err(CliError {
249-
msg: format!("Failed to describe cache clusters: {}", err),
250-
});
220+
let mut clusters = Vec::new();
221+
let mut next_marker: Option<String> = None;
222+
loop {
223+
let response = rate_limit(Arc::clone(&control_plane_limiter), || {
224+
let mut req = elasticache_client
225+
.describe_cache_clusters()
226+
.show_cache_node_info(true);
227+
if let Some(marker) = &next_marker {
228+
req = req.marker(marker);
251229
}
230+
req.send()
231+
})
232+
.await?;
233+
234+
if let Some(aws_clusters) = response.cache_clusters.as_ref() {
235+
clusters.extend_from_slice(aws_clusters);
236+
}
237+
238+
next_marker = response.marker().map(String::from);
239+
if next_marker.is_none() {
240+
break;
252241
}
253242
}
254243

255-
Ok(resources)
244+
clusters
245+
.into_iter()
246+
.map(|cluster| convert_to_resources(cluster, region))
247+
.collect::<Result<Vec<_>, _>>()
248+
.map(|vec| vec.into_iter().flatten().collect())
256249
}
257250

258-
async fn convert_to_resources(
251+
fn convert_to_resources(
259252
cluster: CacheCluster,
260253
region: &str,
261254
) -> Result<Vec<ElastiCacheResource>, CliError> {

momento/src/commands/cloud_linter/metrics.rs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -148,26 +148,20 @@ async fn query_metrics_for_target(
148148
metric_data_queries.push(metric_data_query);
149149
}
150150

151-
let mut metric_stream = client
152-
.get_metric_data()
153-
.start_time(DateTime::from_millis(start_millis))
154-
.end_time(DateTime::from_millis(end_millis))
155-
.set_metric_data_queries(Some(metric_data_queries))
156-
.into_paginator()
157-
.send();
158-
159-
while let Some(result) = rate_limit(Arc::clone(&limiter), || metric_stream.next()).await {
160-
let result = match result {
161-
Ok(res) => res,
162-
Err(e) => {
163-
println!("get_metric_data_error: {:?}", e);
164-
return Err(CliError {
165-
msg: "error from aws api while querying metrics".to_string(),
166-
});
167-
}
168-
};
169-
// let result = result?;
170-
if let Some(mdr_vec) = result.metric_data_results {
151+
let mut next_token: Option<String> = None;
152+
loop {
153+
let response = rate_limit(Arc::clone(&limiter), || {
154+
client
155+
.get_metric_data()
156+
.start_time(DateTime::from_millis(start_millis))
157+
.end_time(DateTime::from_millis(end_millis))
158+
.set_metric_data_queries(Some(metric_data_queries.clone()))
159+
.set_next_token(next_token)
160+
.send()
161+
})
162+
.await?;
163+
164+
if let Some(mdr_vec) = response.metric_data_results {
171165
for mdr in mdr_vec {
172166
let name = mdr.id.ok_or_else(|| CliError {
173167
msg: "Metric has no id".to_string(),
@@ -178,6 +172,11 @@ async fn query_metrics_for_target(
178172
metric_results.push(Metric { name, values });
179173
}
180174
}
175+
176+
next_token = response.next_token;
177+
if next_token.is_none() {
178+
break;
179+
}
181180
}
182181
}
183182

momento/src/commands/cloud_linter/serverless_elasticache.rs

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -231,42 +231,35 @@ async fn describe_caches(
231231
control_plane_limiter: Arc<DefaultDirectRateLimiter>,
232232
region: &str,
233233
) -> Result<Vec<ServerlessElastiCacheResource>, CliError> {
234-
let mut resources = Vec::new();
235-
let mut elasticache_stream = elasticache_client
236-
.describe_serverless_caches()
237-
.into_paginator()
238-
.send();
239-
240-
while let Some(result) = rate_limit(Arc::clone(&control_plane_limiter), || {
241-
elasticache_stream.next()
242-
})
243-
.await
244-
{
245-
match result {
246-
Ok(result) => {
247-
if let Some(aws_caches) = result.serverless_caches {
248-
let mut chunks = Vec::new();
249-
for chunk in aws_caches.chunks(10) {
250-
chunks.push(chunk.to_owned());
251-
}
252-
for clusters in chunks {
253-
for cluster in clusters {
254-
resources.push(convert_to_resource(cluster, region).await?);
255-
}
256-
}
257-
}
258-
}
259-
Err(err) => {
260-
return Err(CliError {
261-
msg: format!("Failed to describe serverless caches: {}", err),
262-
});
234+
let mut caches = Vec::new();
235+
let mut next_token: Option<String> = None;
236+
loop {
237+
let response = rate_limit(Arc::clone(&control_plane_limiter), || {
238+
let mut req = elasticache_client.describe_serverless_caches();
239+
if let Some(token) = &next_token {
240+
req = req.next_token(token);
263241
}
242+
req.send()
243+
})
244+
.await?;
245+
246+
if let Some(aws_caches) = response.serverless_caches.as_ref() {
247+
caches.extend_from_slice(aws_caches);
248+
}
249+
250+
next_token = response.next_token().map(String::from);
251+
if next_token.is_none() {
252+
break;
264253
}
265254
}
266-
Ok(resources)
255+
256+
caches
257+
.into_iter()
258+
.map(|cluster| convert_to_resource(cluster, region))
259+
.collect::<Result<_, _>>()
267260
}
268261

269-
async fn convert_to_resource(
262+
fn convert_to_resource(
270263
cache: ServerlessCache,
271264
region: &str,
272265
) -> Result<ServerlessElastiCacheResource, CliError> {

0 commit comments

Comments
 (0)