Skip to content

Commit d0fa362

Browse files
committed
Add docs.
1 parent 97a756b commit d0fa362

2 files changed

Lines changed: 273 additions & 0 deletions

File tree

docs/utilities/lambda_metadata.md

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
---
2+
title: Lambda Metadata
3+
description: Utility
4+
---
5+
6+
Lambda Metadata provides idiomatic access to the Lambda Metadata Endpoint (LMDS), eliminating boilerplate code for retrieving execution environment metadata like Availability Zone ID.
7+
8+
## Key features
9+
10+
* Retrieve Lambda execution environment metadata with a single method call
11+
* Automatic caching for the sandbox lifetime, avoiding repeated HTTP calls
12+
* Thread-safe access for concurrent executions (compatible with [Lambda Managed Instances](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html){target="_blank"})
13+
* Automatic [SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html){target="_blank"} cache invalidation via [CRaC](https://openjdk.org/projects/crac/){target="_blank"} integration
14+
* Lightweight with minimal external dependencies, using built-in `HttpURLConnection`
15+
* GraalVM support
16+
17+
## Getting started
18+
19+
### Installation
20+
21+
=== "Maven"
22+
23+
```xml hl_lines="3-7"
24+
<dependencies>
25+
...
26+
<dependency>
27+
<groupId>software.amazon.lambda</groupId>
28+
<artifactId>powertools-lambda-metadata</artifactId>
29+
<version>{{ powertools.version }}</version>
30+
</dependency>
31+
...
32+
</dependencies>
33+
```
34+
35+
=== "Gradle"
36+
37+
```groovy hl_lines="6"
38+
repositories {
39+
mavenCentral()
40+
}
41+
42+
dependencies {
43+
implementation 'software.amazon.lambda:powertools-lambda-metadata:{{ powertools.version }}'
44+
}
45+
46+
sourceCompatibility = 11
47+
targetCompatibility = 11
48+
```
49+
50+
### IAM Permissions
51+
52+
No additional IAM permissions are required. The Lambda Metadata Endpoint is available within the Lambda execution environment and uses a Bearer token provided automatically via environment variables.
53+
54+
### Basic usage
55+
56+
Retrieve metadata using `LambdaMetadataClient.get()`:
57+
58+
=== "App.java"
59+
60+
```java hl_lines="1 2 9 10"
61+
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
62+
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;
63+
64+
public class App implements RequestHandler<Object, String> {
65+
66+
@Override
67+
public String handleRequest(Object input, Context context) {
68+
// Fetch metadata (automatically cached after first call)
69+
LambdaMetadata metadata = LambdaMetadataClient.get();
70+
String azId = metadata.getAvailabilityZoneId(); // e.g., "use1-az1"
71+
72+
return "{\"az\": \"" + azId + "\"}";
73+
}
74+
}
75+
```
76+
77+
!!! info "At launch, only `availabilityZoneId` is available. The API is designed to support additional metadata fields as LMDS evolves."
78+
79+
### Caching behavior
80+
81+
Metadata is **cached automatically** after the first call. Subsequent calls return the cached value without making HTTP requests.
82+
83+
=== "CachingExample.java"
84+
85+
```java hl_lines="9 12"
86+
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
87+
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;
88+
89+
public class CachingExample implements RequestHandler<Object, String> {
90+
91+
@Override
92+
public String handleRequest(Object input, Context context) {
93+
// First call: fetches from endpoint and caches
94+
LambdaMetadata metadata = LambdaMetadataClient.get();
95+
96+
// Subsequent calls: returns cached value (no HTTP call)
97+
LambdaMetadata metadataAgain = LambdaMetadataClient.get();
98+
99+
// Both return the same cached instance
100+
assert metadata == metadataAgain;
101+
102+
return "{\"az\": \"" + metadata.getAvailabilityZoneId() + "\"}";
103+
}
104+
}
105+
```
106+
107+
This is safe because metadata (like Availability Zone) never changes during a sandbox's lifetime.
108+
109+
## Advanced
110+
111+
### Eager loading at module level
112+
113+
For predictable latency, fetch metadata at class initialization:
114+
115+
=== "EagerLoadingExample.java"
116+
117+
```java hl_lines="7"
118+
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
119+
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;
120+
121+
public class EagerLoadingExample implements RequestHandler<Object, String> {
122+
123+
// Fetch during cold start (class loading)
124+
private static final LambdaMetadata METADATA = LambdaMetadataClient.get();
125+
126+
@Override
127+
public String handleRequest(Object input, Context context) {
128+
// No latency hit here - already cached
129+
return "{\"az\": \"" + METADATA.getAvailabilityZoneId() + "\"}";
130+
}
131+
}
132+
```
133+
134+
#### SnapStart considerations
135+
136+
When using [SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html){target="_blank"}, the function may restore in a different Availability Zone. The utility automatically handles this by registering with CRaC to invalidate the cache after restore.
137+
138+
Using the same eager loading pattern above, the cache is automatically invalidated on SnapStart restore, ensuring subsequent calls to `LambdaMetadataClient.get()` return refreshed metadata.
139+
140+
!!! note "For module-level usage with SnapStart, ensure `LambdaMetadataClient` is referenced during initialization so the CRaC hook registers before the snapshot is taken."
141+
142+
### Lambda Managed Instances
143+
144+
For [Lambda Managed Instances](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html){target="_blank"} (multi-threaded concurrency), no changes are needed. The utility uses thread-safe caching with `AtomicReference` to ensure correct behavior across concurrent executions on the same instance.
145+
146+
=== "ManagedInstanceHandler.java"
147+
148+
```java hl_lines="9"
149+
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
150+
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;
151+
152+
public class ManagedInstanceHandler implements RequestHandler<Object, String> {
153+
154+
@Override
155+
public String handleRequest(Object input, Context context) {
156+
// Thread-safe: multiple concurrent invocations safely share cached metadata
157+
LambdaMetadata metadata = LambdaMetadataClient.get();
158+
return "{\"az\": \"" + metadata.getAvailabilityZoneId() + "\"}";
159+
}
160+
}
161+
```
162+
163+
### Forcing a refresh
164+
165+
In rare cases where you need to force a refresh of the cached metadata, use the `refresh()` method:
166+
167+
=== "RefreshExample.java"
168+
169+
```java hl_lines="10"
170+
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
171+
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;
172+
173+
public class RefreshExample implements RequestHandler<Object, String> {
174+
175+
@Override
176+
public String handleRequest(Object input, Context context) {
177+
// Force a refresh of the cached metadata
178+
// This makes a new HTTP request to the metadata endpoint
179+
LambdaMetadata metadata = LambdaMetadataClient.refresh();
180+
return "{\"az\": \"" + metadata.getAvailabilityZoneId() + "\"}";
181+
}
182+
}
183+
```
184+
185+
186+
### Error handling
187+
188+
The utility throws `LambdaMetadataException` when the metadata endpoint is unavailable or returns an error:
189+
190+
=== "ErrorHandlingExample.java"
191+
192+
```java hl_lines="2 7 14 18 21"
193+
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
194+
import software.amazon.lambda.powertools.metadata.exception.LambdaMetadataException;
195+
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;
196+
import software.amazon.lambda.powertools.logging.Logging;
197+
import org.slf4j.Logger;
198+
import org.slf4j.LoggerFactory;
199+
import static software.amazon.lambda.powertools.logging.argument.StructuredArguments.entry;
200+
201+
public class ErrorHandlingExample implements RequestHandler<Object, String> {
202+
203+
private static final Logger LOG = LoggerFactory.getLogger(ErrorHandlingExample.class);
204+
205+
@Override
206+
@Logging
207+
public String handleRequest(Object input, Context context) {
208+
String az;
209+
try {
210+
LambdaMetadata metadata = LambdaMetadataClient.get();
211+
az = metadata.getAvailabilityZoneId();
212+
} catch (LambdaMetadataException e) {
213+
LOG.warn("Could not fetch metadata", entry("statusCode", e.getStatusCode()), entry("error", e.getMessage()));
214+
az = "unknown";
215+
}
216+
217+
return "{\"az\": \"" + az + "\"}";
218+
}
219+
}
220+
```
221+
222+
## Using with other Powertools utilities
223+
224+
Lambda Metadata integrates seamlessly with other Powertools utilities to enrich your observability data with Availability Zone information.
225+
226+
=== "IntegratedExample.java"
227+
228+
```java
229+
import software.amazon.lambda.powertools.logging.Logging;
230+
import software.amazon.lambda.powertools.tracing.Tracing;
231+
import software.amazon.lambda.powertools.tracing.TracingUtils;
232+
import software.amazon.lambda.powertools.metrics.FlushMetrics;
233+
import software.amazon.lambda.powertools.metrics.Metrics;
234+
import software.amazon.lambda.powertools.metrics.MetricsFactory;
235+
import software.amazon.lambda.powertools.metrics.model.MetricUnit;
236+
import software.amazon.lambda.powertools.metadata.LambdaMetadata;
237+
import software.amazon.lambda.powertools.metadata.LambdaMetadataClient;
238+
import org.slf4j.Logger;
239+
import org.slf4j.LoggerFactory;
240+
import org.slf4j.MDC;
241+
242+
public class IntegratedExample implements RequestHandler<Object, String> {
243+
244+
private static final Logger LOG = LoggerFactory.getLogger(IntegratedExample.class);
245+
private static final Metrics metrics = MetricsFactory.getMetricsInstance();
246+
247+
@Logging
248+
@Tracing
249+
@FlushMetrics(captureColdStart = true)
250+
@Override
251+
public String handleRequest(Object input, Context context) {
252+
LambdaMetadata metadata = LambdaMetadataClient.get();
253+
String azId = metadata.getAvailabilityZoneId();
254+
255+
// Add AZ as dimension for all metrics
256+
metrics.addDimension("availability_zone_id", azId);
257+
258+
// Add AZ to structured logs
259+
MDC.put("availability_zone_id", azId);
260+
LOG.info("Processing request");
261+
262+
// Add AZ to traces
263+
TracingUtils.putAnnotation("availability_zone_id", azId);
264+
265+
// Add metrics
266+
metrics.addMetric("RequestProcessed", 1, MetricUnit.COUNT);
267+
268+
return "{\"status\": \"ok\"}";
269+
}
270+
}
271+
```

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ nav:
2222
- utilities/validation.md
2323
- utilities/custom_resources.md
2424
- utilities/serialization.md
25+
- utilities/lambda_metadata.md
2526
- Processes:
2627
- processes/maintainers.md
2728
- "Versioning policy": processes/versioning.md
@@ -114,6 +115,7 @@ plugins:
114115
- utilities/batch.md
115116
- utilities/kafka.md
116117
- utilities/large_messages.md
118+
- utilities/lambda_metadata.md
117119
- utilities/validation.md
118120
- utilities/custom_resources.md
119121
- utilities/serialization.md

0 commit comments

Comments
 (0)