Skip to content

Commit 7febeb0

Browse files
Zelda Hesslerjdisanti
authored andcommitted
[smithy-rs] feature: Invocation ID interceptor (#2626)
## Motivation and Context <!--- Why is this change required? What problem does it solve? --> <!--- If it fixes an open issue, please link to the issue here --> part of #1793 ## Description <!--- Describe your changes in detail --> This adds an interceptor for AWS SDK requests. The interceptor is run just before the retry loop and adds a header with name `amz-sdk-invocation-id` and value that's a UUID. AWS services use this identifier to more efficiently process requests. ## Testing <!--- Please describe in detail how you tested your changes --> <!--- Include details of your testing environment, and the tests you ran to --> <!--- see how your change affects other areas of the code, etc. --> This change includes tests ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --------- Co-authored-by: John DiSanti <jdisanti@amazon.com>
1 parent f72e6e9 commit 7febeb0

File tree

4 files changed

+100
-2
lines changed

4 files changed

+100
-2
lines changed

sdk/aws-runtime/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ version = "0.55.2"
4545
path = "../aws-types"
4646
version = "0.55.2"
4747

48+
[dependencies.uuid]
49+
version = "1"
50+
features = ["v4", "fast-rng"]
51+
4852
[dev-dependencies]
4953
proptest = "1"
5054
serde_json = "1"

sdk/aws-runtime/src/invocation_id.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
use aws_smithy_runtime_api::client::interceptors::error::BoxError;
7+
use aws_smithy_runtime_api::client::interceptors::{Interceptor, InterceptorContext};
8+
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
9+
use aws_smithy_runtime_api::config_bag::ConfigBag;
10+
use http::{HeaderName, HeaderValue};
11+
use uuid::Uuid;
12+
13+
#[allow(clippy::declare_interior_mutable_const)] // we will never mutate this
14+
const AMZ_SDK_INVOCATION_ID: HeaderName = HeaderName::from_static("amz-sdk-invocation-id");
15+
16+
/// This interceptor generates a UUID and attaches it to all request attempts made as part of this operation.
17+
#[non_exhaustive]
18+
#[derive(Debug)]
19+
pub struct InvocationIdInterceptor {
20+
id: HeaderValue,
21+
}
22+
23+
impl InvocationIdInterceptor {
24+
/// Creates a new `InvocationIdInterceptor`
25+
pub fn new() -> Self {
26+
Self::default()
27+
}
28+
}
29+
30+
impl Default for InvocationIdInterceptor {
31+
fn default() -> Self {
32+
let id = Uuid::new_v4();
33+
let id = id
34+
.to_string()
35+
.parse()
36+
.expect("UUIDs always produce a valid header value");
37+
Self { id }
38+
}
39+
}
40+
41+
impl Interceptor<HttpRequest, HttpResponse> for InvocationIdInterceptor {
42+
fn modify_before_retry_loop(
43+
&self,
44+
context: &mut InterceptorContext<HttpRequest, HttpResponse>,
45+
_cfg: &mut ConfigBag,
46+
) -> Result<(), BoxError> {
47+
let headers = context.request_mut()?.headers_mut();
48+
headers.append(AMZ_SDK_INVOCATION_ID, self.id.clone());
49+
Ok(())
50+
}
51+
}
52+
53+
#[cfg(test)]
54+
mod tests {
55+
use crate::invocation_id::InvocationIdInterceptor;
56+
use aws_smithy_http::body::SdkBody;
57+
use aws_smithy_runtime_api::client::interceptors::{Interceptor, InterceptorContext};
58+
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest, HttpResponse};
59+
use aws_smithy_runtime_api::config_bag::ConfigBag;
60+
use aws_smithy_runtime_api::type_erasure::TypedBox;
61+
use http::HeaderValue;
62+
63+
fn expect_header<'a>(
64+
context: &'a InterceptorContext<HttpRequest, HttpResponse>,
65+
header_name: &str,
66+
) -> &'a HeaderValue {
67+
context
68+
.request()
69+
.unwrap()
70+
.headers()
71+
.get(header_name)
72+
.unwrap()
73+
}
74+
75+
#[test]
76+
fn test_id_is_generated_and_set() {
77+
let mut context = InterceptorContext::new(TypedBox::new("doesntmatter").erase());
78+
context.set_request(http::Request::builder().body(SdkBody::empty()).unwrap());
79+
80+
let mut config = ConfigBag::base();
81+
let interceptor = InvocationIdInterceptor::new();
82+
interceptor
83+
.modify_before_retry_loop(&mut context, &mut config)
84+
.unwrap();
85+
86+
let header = expect_header(&context, "amz-sdk-invocation-id");
87+
assert_eq!(&interceptor.id, header);
88+
// UUID should include 32 chars and 4 dashes
89+
assert_eq!(interceptor.id.len(), 36);
90+
}
91+
}

sdk/aws-runtime/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ pub mod recursion_detection;
2424

2525
/// Supporting code for user agent headers in the AWS SDK.
2626
pub mod user_agent;
27+
28+
/// Supporting code for invocation ID headers in the AWS SDK.
29+
pub mod invocation_id;

versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
smithy_rs_revision = '826d89b2c89a6044a9d70576a28304d6c2f366fb'
1+
smithy_rs_revision = '631ff01637ee9a6aa2a054a78d4c0250ff7f83a5'
22
aws_doc_sdk_examples_revision = 'f4fc46139c2ea0784e31cadd19b430fcd2bbc21a'
33

44
[manual_interventions]
@@ -31,7 +31,7 @@ source_hash = '5af5b63b3528ac874a7ecb6487f4e6c66d4d90a54116a1b0b5f5e477850bf503'
3131
[crates.aws-runtime]
3232
category = 'AwsRuntime'
3333
version = '0.55.2'
34-
source_hash = '4fd0645b2def7769d26850f668ca7c0d7908afcfa7e529639b4e60da430a3077'
34+
source_hash = '2591913d93a1358cff023ca731a93760f154dc35d6b8527c18bcfca044afb175'
3535

3636
[crates.aws-runtime-api]
3737
category = 'AwsRuntime'

0 commit comments

Comments
 (0)