Skip to content

Commit 2e9179f

Browse files
committed
add custom UA header
1 parent 429dc03 commit 2e9179f

4 files changed

Lines changed: 115 additions & 12 deletions

File tree

sdk/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@
6666
</dependencies>
6767

6868
<build>
69+
<resources>
70+
<resource>
71+
<directory>src/main/resources</directory>
72+
<filtering>true</filtering>
73+
<includes>
74+
<include>**/*.prop</include>
75+
</includes>
76+
</resource>
77+
</resources>
6978
<plugins>
7079
<plugin>
7180
<groupId>org.apache.maven.plugins</groupId>

sdk/src/main/java/software/amazon/lambda/durable/DurableConfig.java

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@
22
// SPDX-License-Identifier: Apache-2.0
33
package software.amazon.lambda.durable;
44

5+
import java.io.IOException;
6+
import java.io.InputStream;
57
import java.time.Duration;
68
import java.util.Objects;
9+
import java.util.Properties;
710
import java.util.concurrent.ExecutorService;
811
import java.util.concurrent.Executors;
912
import org.slf4j.Logger;
1013
import org.slf4j.LoggerFactory;
1114
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
1215
import software.amazon.awssdk.core.SdkSystemSetting;
16+
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
1317
import software.amazon.awssdk.regions.Region;
1418
import software.amazon.awssdk.services.lambda.LambdaClient;
19+
import software.amazon.awssdk.services.lambda.LambdaClientBuilder;
1520
import software.amazon.awssdk.services.lambda.model.GetDurableExecutionStateRequest;
1621
import software.amazon.lambda.durable.client.DurableExecutionClient;
1722
import software.amazon.lambda.durable.client.LambdaDurableFunctionsClient;
@@ -64,6 +69,10 @@ public final class DurableConfig {
6469
*/
6570
private static final String DEFAULT_REGION = "us-east-1";
6671

72+
private static final String VERSION_FILE = "/version.prop";
73+
private static final String PROJECT_VERSION = getProjectVersion(VERSION_FILE);
74+
private static final String USER_AGENT_SUFFIX = "@aws/durable-execution-sdk-java/" + PROJECT_VERSION;
75+
6776
private final DurableExecutionClient durableExecutionClient;
6877
private final SerDes serDes;
6978
private final ExecutorService executorService;
@@ -169,9 +178,9 @@ private static DurableExecutionClient createDefaultDurableExecutionClient() {
169178
logger.debug("AWS_REGION not set, defaulting to: {}", region);
170179
}
171180

172-
var lambdaClient = LambdaClient.builder()
173-
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
174-
.region(Region.of(region))
181+
var lambdaClient = addUserAgentSuffix(LambdaClient.builder()
182+
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
183+
.region(Region.of(region)))
175184
.build();
176185

177186
try {
@@ -194,6 +203,27 @@ private static DurableExecutionClient createDefaultDurableExecutionClient() {
194203
return new LambdaDurableFunctionsClient(lambdaClient);
195204
}
196205

206+
static LambdaClientBuilder addUserAgentSuffix(LambdaClientBuilder builder) {
207+
return builder.overrideConfiguration(builder.overrideConfiguration().toBuilder()
208+
.putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, USER_AGENT_SUFFIX)
209+
.build());
210+
}
211+
212+
private static String getProjectVersion(String versionFile) {
213+
InputStream stream = DurableConfig.class.getResourceAsStream(versionFile);
214+
if (stream == null) {
215+
return "UNKNOWN";
216+
}
217+
Properties props = new Properties();
218+
try {
219+
props.load(stream);
220+
stream.close();
221+
return (String) props.get("version");
222+
} catch (IOException e) {
223+
return "UNKNOWN";
224+
}
225+
}
226+
197227
/**
198228
* Creates a default ExecutorService for running user-defined operations. Uses a cached thread pool with daemon
199229
* threads by default.
@@ -230,23 +260,23 @@ private Builder() {}
230260
* <p>Example:
231261
*
232262
* <pre>{@code
233-
* LambdaClient lambdaClient = LambdaClient.builder()
263+
* LambdaClientBuilder lambdaClientBuilder = LambdaClient.builder()
234264
* .region(Region.US_WEST_2)
235-
* .credentialsProvider(ProfileCredentialsProvider.create("my-profile"))
236-
* .build();
265+
* .credentialsProvider(ProfileCredentialsProvider.create("my-profile"));
237266
*
238267
* DurableConfig.builder()
239-
* .withLambdaClient(lambdaClient)
268+
* .withLambdaClientBuilder(lambdaClientBuilder)
240269
* .build();
241270
* }</pre>
242271
*
243-
* @param lambdaClient Custom LambdaClient instance
272+
* @param lambdaClientBuilder Custom LambdaClientBuilder instance
244273
* @return This builder
245274
* @throws NullPointerException if lambdaClient is null
246275
*/
247-
public Builder withLambdaClient(LambdaClient lambdaClient) {
248-
Objects.requireNonNull(lambdaClient, "LambdaClient cannot be null");
249-
this.durableExecutionClient = new LambdaDurableFunctionsClient(lambdaClient);
276+
public Builder withLambdaClientBuilder(LambdaClientBuilder lambdaClientBuilder) {
277+
Objects.requireNonNull(lambdaClientBuilder, "LambdaClient cannot be null");
278+
this.durableExecutionClient = new LambdaDurableFunctionsClient(
279+
addUserAgentSuffix(lambdaClientBuilder).build());
250280
return this;
251281
}
252282

@@ -255,7 +285,7 @@ public Builder withLambdaClient(LambdaClient lambdaClient) {
255285
*
256286
* <p><b>Note:</b> This method is primarily intended for testing with mock clients (e.g.,
257287
* {@code LocalMemoryExecutionClient}). For production use with a custom AWS SDK client, prefer
258-
* {@link #withLambdaClient(LambdaClient)}.
288+
* {@link #withLambdaClientBuilder(LambdaClientBuilder)}.
259289
*
260290
* @param durableExecutionClient Custom DurableExecutionClient instance
261291
* @return This builder
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
version=${project.version}

sdk/src/test/java/software/amazon/lambda/durable/DurableConfigTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
import static org.junit.jupiter.api.Assertions.assertNotSame;
1010
import static org.junit.jupiter.api.Assertions.assertSame;
1111
import static org.junit.jupiter.api.Assertions.assertThrows;
12+
import static org.junit.jupiter.api.Assertions.assertTrue;
1213
import static org.mockito.Mockito.mock;
1314

1415
import java.util.concurrent.ExecutorService;
1516
import org.junit.jupiter.api.BeforeEach;
1617
import org.junit.jupiter.api.Test;
18+
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
19+
import software.amazon.awssdk.services.lambda.LambdaClient;
1720
import software.amazon.lambda.durable.client.DurableExecutionClient;
1821
import software.amazon.lambda.durable.client.LambdaDurableFunctionsClient;
1922
import software.amazon.lambda.durable.serde.JacksonSerDes;
@@ -231,4 +234,64 @@ void testBuilder_PartialConfiguration_FillsDefaults() {
231234
assertInstanceOf(LambdaDurableFunctionsClient.class, config.getDurableExecutionClient());
232235
assertNotNull(config.getExecutorService());
233236
}
237+
238+
@Test
239+
void testBuilder_WithLambdaClientBuilder_CreatesLambdaDurableFunctionsClient() {
240+
var lambdaClientBuilder = LambdaClient.builder()
241+
.region(software.amazon.awssdk.regions.Region.US_WEST_2)
242+
.credentialsProvider(software.amazon.awssdk.auth.credentials.StaticCredentialsProvider.create(
243+
software.amazon.awssdk.auth.credentials.AwsBasicCredentials.create("test", "test")));
244+
245+
var config = DurableConfig.builder()
246+
.withLambdaClientBuilder(lambdaClientBuilder)
247+
.build();
248+
249+
assertNotNull(config.getDurableExecutionClient());
250+
assertInstanceOf(LambdaDurableFunctionsClient.class, config.getDurableExecutionClient());
251+
}
252+
253+
@Test
254+
void testBuilder_WithLambdaClientBuilder_NullThrowsException() {
255+
var builder = DurableConfig.builder();
256+
257+
var exception = assertThrows(NullPointerException.class, () -> builder.withLambdaClientBuilder(null));
258+
259+
assertEquals("LambdaClient cannot be null", exception.getMessage());
260+
}
261+
262+
@Test
263+
void testAddUserAgentSuffix_SetsUserAgentOnBuilder() {
264+
var lambdaClientBuilder = LambdaClient.builder();
265+
266+
var result = DurableConfig.addUserAgentSuffix(lambdaClientBuilder);
267+
268+
var overrideConfig = result.overrideConfiguration();
269+
var userAgentSuffix = overrideConfig.advancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX);
270+
assertTrue(userAgentSuffix.isPresent(), "USER_AGENT_SUFFIX should be set");
271+
assertTrue(
272+
userAgentSuffix.get().contains("@aws/durable-execution-sdk-java/"),
273+
"User agent suffix should contain SDK identifier, got: " + userAgentSuffix.get());
274+
}
275+
276+
@Test
277+
void testAddUserAgentSuffix_PreservesExistingConfiguration() {
278+
var lambdaClientBuilder =
279+
LambdaClient.builder().overrideConfiguration(c -> c.putHeader("X-Custom-Header", "test-value"));
280+
281+
var result = DurableConfig.addUserAgentSuffix(lambdaClientBuilder);
282+
283+
var overrideConfig = result.overrideConfiguration();
284+
var userAgentSuffix = overrideConfig.advancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX);
285+
assertTrue(userAgentSuffix.isPresent());
286+
assertTrue(userAgentSuffix.get().contains("@aws/durable-execution-sdk-java/"));
287+
}
288+
289+
@Test
290+
void testAddUserAgentSuffix_ReturnsSameBuilderInstance() {
291+
var lambdaClientBuilder = LambdaClient.builder();
292+
293+
var result = DurableConfig.addUserAgentSuffix(lambdaClientBuilder);
294+
295+
assertSame(lambdaClientBuilder, result);
296+
}
234297
}

0 commit comments

Comments
 (0)