Skip to content

Commit fd40114

Browse files
fix(util-user-agent-node): should memoize app id (#2223)
* fix(util-user-agent-node): should only load app id once * fix(util-user-agent-node): address feedbacks Co-authored-by: Tyson Andre <[email protected]>
1 parent 5ae46f6 commit fd40114

File tree

2 files changed

+49
-16
lines changed

2 files changed

+49
-16
lines changed

packages/util-user-agent-node/src/index.spec.ts

+39-7
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,17 @@ jest.mock("@aws-sdk/node-config-provider", () => ({
1616
loadConfig: () => mockAppIdLoader,
1717
}));
1818

19+
import { UserAgent } from "@aws-sdk/types";
20+
1921
import { defaultUserAgent } from ".";
2022

23+
const validateUserAgent = (userAgent: UserAgent, expected: UserAgent) => {
24+
expect(userAgent.length).toBe(expected.length);
25+
for (const pair of expected) {
26+
expect(userAgent).toContainEqual(pair);
27+
}
28+
};
29+
2130
describe("defaultUserAgent", () => {
2231
beforeEach(() => {
2332
jest.resetAllMocks();
@@ -27,31 +36,54 @@ describe("defaultUserAgent", () => {
2736
jest.clearAllMocks();
2837
});
2938

39+
const basicUserAgent: UserAgent = [
40+
["aws-sdk-js", "0.1.0"],
41+
["api/s3", "0.1.0"],
42+
["os/darwin", "19.6.0"],
43+
["lang/js"],
44+
["md/nodejs", "14.13.1"],
45+
];
46+
3047
it("should response basic node default user agent", async () => {
3148
const userAgent = await defaultUserAgent({ serviceId: "s3", clientVersion: "0.1.0" })();
32-
expect(userAgent).toContainEqual(["aws-sdk-js", "0.1.0"]);
33-
expect(userAgent).toContainEqual(["api/s3", "0.1.0"]);
34-
expect(userAgent).toContainEqual(["os/darwin", "19.6.0"]);
35-
expect(userAgent).toContainEqual(["lang/js"]);
49+
validateUserAgent(userAgent, basicUserAgent);
3650
});
3751

3852
it("should skip api version if service id is not supplied", async () => {
3953
const userAgent = await defaultUserAgent({ serviceId: undefined, clientVersion: "0.1.0" })();
40-
expect(userAgent).not.toContainEqual(["api/s3", "0.1.0"]);
54+
validateUserAgent(
55+
userAgent,
56+
basicUserAgent.filter((pair) => pair[0] !== "api/s3")
57+
);
4158
});
4259

4360
it("should add AWS_EXECUTION_ENV", async () => {
4461
//@ts-ignore mock environmental variables
4562
mockEnv.AWS_EXECUTION_ENV = "lambda";
4663
const userAgent = await defaultUserAgent({ serviceId: "s3", clientVersion: "0.1.0" })();
47-
expect(userAgent).toContainEqual(["exec-env/lambda"]);
64+
const expectedUserAgent: UserAgent = [...basicUserAgent, ["exec-env/lambda"]];
65+
validateUserAgent(userAgent, expectedUserAgent);
66+
//@ts-ignore mock environmental variables
67+
delete mockEnv.AWS_EXECUTION_ENV;
4868
});
4969

5070
it("should load app id if available", async () => {
5171
mockAppIdLoader.mockClear();
5272
const appId = "appId12345";
5373
mockAppIdLoader.mockResolvedValue(appId);
5474
const userAgent = await defaultUserAgent({ serviceId: "s3", clientVersion: "0.1.0" })();
55-
expect(userAgent).toContainEqual([`app/${appId}`]);
75+
const expectedUserAgent: UserAgent = [...basicUserAgent, [`app/${appId}`]];
76+
validateUserAgent(userAgent, expectedUserAgent);
77+
});
78+
79+
it("should memoize app id", async () => {
80+
mockAppIdLoader.mockClear();
81+
const appId = "appId12345";
82+
mockAppIdLoader.mockResolvedValue(appId);
83+
const userAgentProvider = defaultUserAgent({ serviceId: "s3", clientVersion: "0.1.0" });
84+
const expectedUserAgent: UserAgent = [...basicUserAgent, [`app/${appId}`]];
85+
validateUserAgent(await userAgentProvider(), expectedUserAgent);
86+
validateUserAgent(await userAgentProvider(), expectedUserAgent);
87+
expect(mockAppIdLoader).toBeCalledTimes(1);
5688
});
5789
});

packages/util-user-agent-node/src/index.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ interface DefaultUserAgentOptions {
1414
/**
1515
* Collect metrics from runtime to put into user agent.
1616
*/
17-
export const defaultUserAgent = ({
18-
serviceId,
19-
clientVersion,
20-
}: DefaultUserAgentOptions): Provider<UserAgent> => async () => {
17+
export const defaultUserAgent = ({ serviceId, clientVersion }: DefaultUserAgentOptions): Provider<UserAgent> => {
2118
const sections: UserAgent = [
2219
// sdk-metadata
2320
["aws-sdk-js", clientVersion],
@@ -40,14 +37,18 @@ export const defaultUserAgent = ({
4037
sections.push([`exec-env/${env.AWS_EXECUTION_ENV}`]);
4138
}
4239

43-
const appId = await loadConfig<string | undefined>({
40+
const appIdPromise = loadConfig<string | undefined>({
4441
environmentVariableSelector: (env) => env[UA_APP_ID_ENV_NAME],
4542
configFileSelector: (profile) => profile[UA_APP_ID_INI_NAME],
4643
default: undefined,
4744
})();
48-
if (appId) {
49-
sections.push([`app/${appId}`]);
50-
}
5145

52-
return sections;
46+
let resolvedUserAgent: UserAgent | undefined = undefined;
47+
return async () => {
48+
if (!resolvedUserAgent) {
49+
const appId = await appIdPromise;
50+
resolvedUserAgent = appId ? [...sections, [`app/${appId}`]] : [...sections];
51+
}
52+
return resolvedUserAgent;
53+
};
5354
};

0 commit comments

Comments
 (0)