Skip to content

Commit 2b1467b

Browse files
authored
Merge branch 'main' into dependabot/maven/aws.xray.recorder.version-2.18.3
2 parents c9ce7ba + 07ff3b2 commit 2b1467b

File tree

21 files changed

+3964
-20
lines changed

21 files changed

+3964
-20
lines changed

Priming.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Automatic Priming for AWS Lambda Powertools Java
2+
3+
## Table of Contents
4+
- [Overview](#overview)
5+
- [Implementation Steps](#general-implementation-steps)
6+
- [Known Issues](#known-issues-and-solutions)
7+
- [Reference Implementation](#reference-implementation)
8+
9+
## Overview
10+
Priming is the process of preloading dependencies and initializing resources during the INIT phase, rather than during the INVOKE phase to further optimize startup performance with SnapStart.
11+
This is required because Java frameworks that use dependency injection load classes into memory when these classes are explicitly invoked, which typically happens during Lambda’s INVOKE phase.
12+
13+
This documentation provides guidance for automatic class priming in Powertools for AWS Lambda Java modules.
14+
15+
16+
## Implementation Steps
17+
Classes are proactively loaded using Java runtime hooks which are part of the open source [CRaC (Coordinated Restore at Checkpoint) project](https://openjdk.org/projects/crac/).
18+
Implementations across the project use the `beforeCheckpoint()` hook, to prime Snapstart-enabled Java functions via Class Priming.
19+
In order to generate the `classloaded.txt` file for a Java module in this project, follow these general steps.
20+
21+
1. **Add Maven Profile**
22+
- Add maven test profile with the following VM argument for generating classes loaded files.
23+
```shell
24+
-Xlog:class+load=info:classesloaded.txt
25+
```
26+
- You can find an example of this in `generate-classesloaded-file` profile in this [pom.xml](powertools-metrics/pom.xml).
27+
28+
2. **Generate classes loaded file**
29+
- Run tests with `-Pgenerate-classesloaded-file` profile.
30+
```shell
31+
mvn -Pgenerate-classesloaded-file clean test
32+
```
33+
- This will generate a file named `classesloaded.txt` in the target directory of the module.
34+
35+
3. **Cleanup the file**
36+
- The classes loaded file generated in Step 2 has the format
37+
`[0.054s][info][class,load] java.lang.Object source: shared objects file`
38+
but we are only interested in `java.lang.Object` - the fully qualified class name.
39+
- To strip the lines to include only the fully qualified class name,
40+
Use the following regex to replace with empty string.
41+
- `^\[[\[\]0-9.a-z,]+ ` (to replace the left part)
42+
- `( source: )[0-9a-z :/._$-]+` (to replace the right part)
43+
44+
4. **Add file to resources**
45+
- Move the cleaned-up file to the corresponding `src/main/resources` directory of the module. See [example](powertools-metrics/src/main/resources/classesloaded.txt).
46+
47+
5. **Register and checkpoint**
48+
- A class, usually the entry point of the module, should register the CRaC resource in the constructor. [Example](powertools-metrics/src/main/java/software/amazon/lambda/powertools/metrics/MetricsFactory.java)
49+
- Note that AspectJ aspect is not suitable for this purpose, as it does not work with CRaC.
50+
- Add the `beforeCheckpoint()` hook in the same class to invoke `ClassPreLoader.preloadClasses()`. The `ClassPreLoader` class is implemented in `powertools-common` module.
51+
- This will ensure that the classes are already pre-loaded by the Snapstart RESTORE operation leading to a shorter INIT duration.
52+
53+
54+
## Known Issues
55+
- This is a manual process at the moment, but it can be automated in the future.
56+
- `classesloaded.txt` file includes test classes as well because the file is generated while running tests. This is not a problem because all the classes that are not found are ignored by `ClassPreLoader.preloadClasses()`. Also `beforeCheckpoint()` hook is not time-sensitive, it only runs once when a new Lambda version gets published.
57+
58+
## Reference Implementation
59+
Working example is available in the [powertools-metrics](powertools-metrics/src/main/java/software/amazon/lambda/powertools/metrics/MetricsFactory.java).

docs/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM squidfunk/mkdocs-material@sha256:0bfdba448e93984191246f7a28abeacc79f789e7e9cf0c639a48fe4365e880a7
1+
FROM squidfunk/mkdocs-material@sha256:bb7b015690d9fb5ef0dbc98ca3520f153aa43129fb96aec5ca54c9154dc3b729
22

33
COPY requirements.txt /tmp/
44
RUN pip install --require-hashes -r /tmp/requirements.txt

examples/powertools-examples-batch/deploy/sqs/template.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Resources:
6565
DemoSQSSenderFunction:
6666
Type: AWS::Serverless::Function
6767
Properties:
68+
Tracing: Active
6869
CodeUri: ../..
6970
Handler: org.demo.batch.sqs.SqsBatchSender::handleRequest
7071
Environment:
@@ -173,7 +174,6 @@ Resources:
173174
Action:
174175
- s3:PutObject
175176
Resource: !Sub ${Bucket.Arn}/*
176-
177177
Events:
178178
MySQSEvent:
179179
Type: SQS

examples/powertools-examples-batch/src/main/java/org/demo/batch/sqs/AbstractSqsBatchHandler.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,22 @@
1414

1515
package org.demo.batch.sqs;
1616

17-
import com.amazonaws.services.lambda.runtime.Context;
18-
import com.fasterxml.jackson.databind.ObjectMapper;
1917
import java.io.File;
2018
import java.io.IOException;
2119
import java.util.Arrays;
2220
import java.util.Random;
21+
2322
import org.demo.batch.model.Product;
2423
import org.slf4j.Logger;
2524
import org.slf4j.LoggerFactory;
2625
import org.slf4j.MDC;
26+
27+
import com.fasterxml.jackson.databind.ObjectMapper;
28+
2729
import software.amazon.awssdk.core.sync.RequestBody;
2830
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
2931
import software.amazon.awssdk.services.s3.S3Client;
3032
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
31-
import software.amazon.lambda.powertools.logging.Logging;
3233
import software.amazon.lambda.powertools.tracing.Tracing;
3334
import software.amazon.lambda.powertools.tracing.TracingUtils;
3435

@@ -43,23 +44,23 @@ public class AbstractSqsBatchHandler {
4344
* Simulate some processing (I/O + S3 put request)
4445
* @param p deserialized product
4546
*/
46-
@Logging
4747
@Tracing
4848
protected void processMessage(Product p) {
4949
TracingUtils.putAnnotation("productId", p.getId());
5050
TracingUtils.putAnnotation("Thread", Thread.currentThread().getName());
5151
MDC.put("product", String.valueOf(p.getId()));
5252
LOGGER.info("Processing product {}", p);
5353

54-
char c = (char)(r.nextInt(26) + 'a');
54+
char c = (char) (r.nextInt(26) + 'a');
5555
char[] chars = new char[1024 * 1000];
5656
Arrays.fill(chars, c);
5757
p.setName(new String(chars));
5858
try {
59-
File file = new File("/tmp/"+p.getId()+".json");
59+
File file = new File("/tmp/" + p.getId() + ".json");
6060
mapper.writeValue(file, p);
6161
s3.putObject(
62-
PutObjectRequest.builder().bucket(bucket).key(p.getId()+".json").build(), RequestBody.fromFile(file));
62+
PutObjectRequest.builder().bucket(bucket).key(p.getId() + ".json").build(),
63+
RequestBody.fromFile(file));
6364
} catch (IOException e) {
6465
throw new RuntimeException(e);
6566
} finally {

examples/powertools-examples-cloudformation/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<maven.compiler.target>11</maven.compiler.target>
1515
<lambda.core.version>1.3.0</lambda.core.version>
1616
<lambda.events.version>3.16.1</lambda.events.version>
17-
<aws.sdk.version>2.32.5</aws.sdk.version>
17+
<aws.sdk.version>2.32.10</aws.sdk.version>
1818
<aspectj.version>1.9.20.1</aspectj.version>
1919

2020
</properties>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bin/

examples/powertools-examples-idempotency/src/main/java/helloworld/App.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import software.amazon.lambda.powertools.idempotency.Idempotent;
3535
import software.amazon.lambda.powertools.idempotency.persistence.dynamodb.DynamoDBPersistenceStore;
3636
import software.amazon.lambda.powertools.logging.Logging;
37+
import software.amazon.lambda.powertools.tracing.Tracing;
3738
import software.amazon.lambda.powertools.utilities.JsonConfig;
3839

3940
public class App implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
@@ -91,6 +92,7 @@ public App(DynamoDbClient client) {
9192
*/
9293
@Idempotent // The magic is here!
9394
@Logging(logEvent = true)
95+
@Tracing
9496
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
9597
Map<String, String> headers = new HashMap<>();
9698

@@ -130,6 +132,7 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv
130132
* @return The contents of the given URL
131133
* @throws IOException
132134
*/
135+
@Tracing
133136
private String getPageContents(String address) throws IOException {
134137
URL url = new URL(address);
135138
try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration>
3+
<Appenders>
4+
<Console name="JsonAppender" target="SYSTEM_OUT">
5+
<JsonTemplateLayout eventTemplateUri="classpath:LambdaJsonLayout.json" />
6+
</Console>
7+
</Appenders>
8+
<Loggers>
9+
<Logger name="JsonLogger" level="INFO" additivity="false">
10+
<AppenderRef ref="JsonAppender" />
11+
</Logger>
12+
<Root level="info">
13+
<AppenderRef ref="JsonAppender" />
14+
</Root>
15+
</Loggers>
16+
</Configuration>

examples/powertools-examples-kafka/src/main/java/org/demo/kafka/protobuf/ProtobufProduct.java

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/powertools-examples-kafka/src/main/java/org/demo/kafka/protobuf/ProtobufProductOrBuilder.java

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)