Skip to content

Commit 6b894df

Browse files
authored
lazily initialize lite client (#524)
* lazily initialize lite client * remove console log * Create dull-lobsters-hope.md
1 parent 8bd6523 commit 6b894df

File tree

4 files changed

+147
-128
lines changed

4 files changed

+147
-128
lines changed

.changeset/dull-lobsters-hope.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/aws": patch
3+
---
4+
5+
lazily initialize lite client

packages/open-next/src/cache/incremental/s3-lite.ts

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
12
import { AwsClient } from "aws4fetch";
23
import path from "path";
34
import { IgnorableError, RecoverableError } from "utils/error";
@@ -7,24 +8,33 @@ import { parseNumberFromEnv } from "../../adapters/util";
78
import { Extension } from "../next-types";
89
import { IncrementalCache } from "./types";
910

10-
const {
11-
CACHE_BUCKET_REGION,
12-
CACHE_BUCKET_KEY_PREFIX,
13-
NEXT_BUILD_ID,
14-
CACHE_BUCKET_NAME,
15-
} = process.env;
11+
let awsClient: AwsClient | null = null;
1612

17-
const awsClient = new AwsClient({
18-
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
19-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
20-
sessionToken: process.env.AWS_SESSION_TOKEN,
21-
region: CACHE_BUCKET_REGION,
22-
retries: parseNumberFromEnv(process.env.AWS_SDK_S3_MAX_ATTEMPTS),
23-
});
13+
const getAwsClient = () => {
14+
const { CACHE_BUCKET_REGION } = process.env;
15+
if (awsClient) {
16+
return awsClient;
17+
} else {
18+
awsClient = new AwsClient({
19+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
20+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
21+
sessionToken: process.env.AWS_SESSION_TOKEN,
22+
region: CACHE_BUCKET_REGION,
23+
retries: parseNumberFromEnv(process.env.AWS_SDK_S3_MAX_ATTEMPTS),
24+
});
25+
return awsClient;
26+
}
27+
};
2428

25-
const awsFetch = customFetchClient(awsClient);
29+
const awsFetch = async (key: string, options: RequestInit) => {
30+
const { CACHE_BUCKET_REGION, CACHE_BUCKET_NAME } = process.env;
31+
const client = getAwsClient();
32+
const url = `https://${CACHE_BUCKET_NAME}.s3.${CACHE_BUCKET_REGION}.amazonaws.com/${key}`;
33+
return customFetchClient(client)(url, options);
34+
};
2635

2736
function buildS3Key(key: string, extension: Extension) {
37+
const { CACHE_BUCKET_KEY_PREFIX, NEXT_BUILD_ID } = process.env;
2838
return path.posix.join(
2939
CACHE_BUCKET_KEY_PREFIX ?? "",
3040
extension === "fetch" ? "__fetch" : "",
@@ -36,10 +46,7 @@ function buildS3Key(key: string, extension: Extension) {
3646
const incrementalCache: IncrementalCache = {
3747
async get(key, isFetch) {
3848
const result = await awsFetch(
39-
`https://${CACHE_BUCKET_NAME}.s3.${CACHE_BUCKET_REGION}.amazonaws.com/${buildS3Key(
40-
key,
41-
isFetch ? "fetch" : "cache",
42-
)}`,
49+
buildS3Key(key, isFetch ? "fetch" : "cache"),
4350
{
4451
method: "GET",
4552
},
@@ -61,10 +68,7 @@ const incrementalCache: IncrementalCache = {
6168
},
6269
async set(key, value, isFetch): Promise<void> {
6370
const response = await awsFetch(
64-
`https://${CACHE_BUCKET_NAME}.s3.${CACHE_BUCKET_REGION}.amazonaws.com/${buildS3Key(
65-
key,
66-
isFetch ? "fetch" : "cache",
67-
)}`,
71+
buildS3Key(key, isFetch ? "fetch" : "cache"),
6872
{
6973
method: "PUT",
7074
body: JSON.stringify(value),
@@ -75,15 +79,9 @@ const incrementalCache: IncrementalCache = {
7579
}
7680
},
7781
async delete(key): Promise<void> {
78-
const response = await awsFetch(
79-
`https://${CACHE_BUCKET_NAME}.s3.${CACHE_BUCKET_REGION}.amazonaws.com/${buildS3Key(
80-
key,
81-
"cache",
82-
)}`,
83-
{
84-
method: "DELETE",
85-
},
86-
);
82+
const response = await awsFetch(buildS3Key(key, "cache"), {
83+
method: "DELETE",
84+
});
8785
if (response.status !== 204) {
8886
throw new RecoverableError(`Failed to delete cache: ${response.status}`);
8987
}

packages/open-next/src/cache/tag/dynamodb-lite.ts

Lines changed: 76 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
12
import { AwsClient } from "aws4fetch";
23
import path from "path";
34
import { RecoverableError } from "utils/error";
@@ -11,18 +12,46 @@ import {
1112
} from "./constants";
1213
import { TagCache } from "./types";
1314

14-
const { CACHE_BUCKET_REGION, CACHE_DYNAMO_TABLE, NEXT_BUILD_ID } = process.env;
15+
let awsClient: AwsClient | null = null;
1516

16-
const awsClient = new AwsClient({
17-
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
18-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
19-
sessionToken: process.env.AWS_SESSION_TOKEN,
20-
region: CACHE_BUCKET_REGION,
21-
retries: parseNumberFromEnv(process.env.AWS_SDK_S3_MAX_ATTEMPTS),
22-
});
23-
const awsFetch = customFetchClient(awsClient);
17+
const getAwsClient = () => {
18+
const { CACHE_BUCKET_REGION } = process.env;
19+
if (awsClient) {
20+
return awsClient;
21+
} else {
22+
awsClient = new AwsClient({
23+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
24+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
25+
sessionToken: process.env.AWS_SESSION_TOKEN,
26+
region: CACHE_BUCKET_REGION,
27+
retries: parseNumberFromEnv(process.env.AWS_SDK_S3_MAX_ATTEMPTS),
28+
});
29+
return awsClient;
30+
}
31+
};
32+
const awsFetch = (
33+
body: RequestInit["body"],
34+
type: "query" | "batchWrite" = "query",
35+
) => {
36+
const { CACHE_BUCKET_REGION } = process.env;
37+
const client = getAwsClient();
38+
return customFetchClient(client)(
39+
`https://dynamodb.${CACHE_BUCKET_REGION}.amazonaws.com`,
40+
{
41+
method: "POST",
42+
headers: {
43+
"Content-Type": "application/x-amz-json-1.0",
44+
"X-Amz-Target": `DynamoDB_20120810.${
45+
type === "query" ? "Query" : "BatchWriteItem"
46+
}`,
47+
},
48+
body,
49+
},
50+
);
51+
};
2452

2553
function buildDynamoKey(key: string) {
54+
const { NEXT_BUILD_ID } = process.env;
2655
// FIXME: We should probably use something else than path.join here
2756
// this could transform some fetch cache key into a valid path
2857
return path.posix.join(NEXT_BUILD_ID ?? "", key);
@@ -40,26 +69,19 @@ const tagCache: TagCache = {
4069
async getByPath(path) {
4170
try {
4271
if (globalThis.disableDynamoDBCache) return [];
72+
const { CACHE_DYNAMO_TABLE, NEXT_BUILD_ID } = process.env;
4373
const result = await awsFetch(
44-
`https://dynamodb.${CACHE_BUCKET_REGION}.amazonaws.com`,
45-
{
46-
method: "POST",
47-
headers: {
48-
"Content-Type": "application/x-amz-json-1.0",
49-
"X-Amz-Target": "DynamoDB_20120810.Query",
74+
JSON.stringify({
75+
TableName: CACHE_DYNAMO_TABLE,
76+
IndexName: "revalidate",
77+
KeyConditionExpression: "#key = :key",
78+
ExpressionAttributeNames: {
79+
"#key": "path",
5080
},
51-
body: JSON.stringify({
52-
TableName: CACHE_DYNAMO_TABLE,
53-
IndexName: "revalidate",
54-
KeyConditionExpression: "#key = :key",
55-
ExpressionAttributeNames: {
56-
"#key": "path",
57-
},
58-
ExpressionAttributeValues: {
59-
":key": { S: buildDynamoKey(path) },
60-
},
61-
}),
62-
},
81+
ExpressionAttributeValues: {
82+
":key": { S: buildDynamoKey(path) },
83+
},
84+
}),
6385
);
6486
if (result.status !== 200) {
6587
throw new RecoverableError(
@@ -80,25 +102,18 @@ const tagCache: TagCache = {
80102
async getByTag(tag) {
81103
try {
82104
if (globalThis.disableDynamoDBCache) return [];
105+
const { CACHE_DYNAMO_TABLE, NEXT_BUILD_ID } = process.env;
83106
const result = await awsFetch(
84-
`https://dynamodb.${CACHE_BUCKET_REGION}.amazonaws.com`,
85-
{
86-
method: "POST",
87-
headers: {
88-
"Content-Type": "application/x-amz-json-1.0",
89-
"X-Amz-Target": "DynamoDB_20120810.Query",
107+
JSON.stringify({
108+
TableName: CACHE_DYNAMO_TABLE,
109+
KeyConditionExpression: "#tag = :tag",
110+
ExpressionAttributeNames: {
111+
"#tag": "tag",
90112
},
91-
body: JSON.stringify({
92-
TableName: CACHE_DYNAMO_TABLE,
93-
KeyConditionExpression: "#tag = :tag",
94-
ExpressionAttributeNames: {
95-
"#tag": "tag",
96-
},
97-
ExpressionAttributeValues: {
98-
":tag": { S: buildDynamoKey(tag) },
99-
},
100-
}),
101-
},
113+
ExpressionAttributeValues: {
114+
":tag": { S: buildDynamoKey(tag) },
115+
},
116+
}),
102117
);
103118
if (result.status !== 200) {
104119
throw new RecoverableError(`Failed to get by tag: ${result.status}`);
@@ -119,29 +134,22 @@ const tagCache: TagCache = {
119134
async getLastModified(key, lastModified) {
120135
try {
121136
if (globalThis.disableDynamoDBCache) return lastModified ?? Date.now();
137+
const { CACHE_DYNAMO_TABLE } = process.env;
122138
const result = await awsFetch(
123-
`https://dynamodb.${CACHE_BUCKET_REGION}.amazonaws.com`,
124-
{
125-
method: "POST",
126-
headers: {
127-
"Content-Type": "application/x-amz-json-1.0",
128-
"X-Amz-Target": "DynamoDB_20120810.Query",
139+
JSON.stringify({
140+
TableName: CACHE_DYNAMO_TABLE,
141+
IndexName: "revalidate",
142+
KeyConditionExpression:
143+
"#key = :key AND #revalidatedAt > :lastModified",
144+
ExpressionAttributeNames: {
145+
"#key": "path",
146+
"#revalidatedAt": "revalidatedAt",
129147
},
130-
body: JSON.stringify({
131-
TableName: CACHE_DYNAMO_TABLE,
132-
IndexName: "revalidate",
133-
KeyConditionExpression:
134-
"#key = :key AND #revalidatedAt > :lastModified",
135-
ExpressionAttributeNames: {
136-
"#key": "path",
137-
"#revalidatedAt": "revalidatedAt",
138-
},
139-
ExpressionAttributeValues: {
140-
":key": { S: buildDynamoKey(key) },
141-
":lastModified": { N: String(lastModified ?? 0) },
142-
},
143-
}),
144-
},
148+
ExpressionAttributeValues: {
149+
":key": { S: buildDynamoKey(key) },
150+
":lastModified": { N: String(lastModified ?? 0) },
151+
},
152+
}),
145153
);
146154
if (result.status !== 200) {
147155
throw new RecoverableError(
@@ -159,6 +167,7 @@ const tagCache: TagCache = {
159167
},
160168
async writeTags(tags) {
161169
try {
170+
const { CACHE_DYNAMO_TABLE } = process.env;
162171
if (globalThis.disableDynamoDBCache) return;
163172
const dataChunks = chunk(tags, MAX_DYNAMO_BATCH_WRITE_ITEM_COUNT).map(
164173
(Items) => ({
@@ -181,15 +190,8 @@ const tagCache: TagCache = {
181190
await Promise.all(
182191
paramsChunk.map(async (params) => {
183192
const response = await awsFetch(
184-
`https://dynamodb.${CACHE_BUCKET_REGION}.amazonaws.com`,
185-
{
186-
method: "POST",
187-
headers: {
188-
"Content-Type": "application/x-amz-json-1.0",
189-
"X-Amz-Target": "DynamoDB_20120810.BatchWriteItem",
190-
},
191-
body: JSON.stringify(params),
192-
},
193+
JSON.stringify(params),
194+
"batchWrite",
193195
);
194196
if (response.status !== 200) {
195197
throw new RecoverableError(

packages/open-next/src/queue/sqs-lite.ts

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,48 @@ import { customFetchClient } from "utils/fetch";
55
import { error } from "../adapters/logger";
66
import { Queue } from "./types";
77

8-
// Expected environment variables
9-
const { REVALIDATION_QUEUE_REGION, REVALIDATION_QUEUE_URL } = process.env;
8+
let awsClient: AwsClient | null = null;
109

11-
const awsClient = new AwsClient({
12-
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
13-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
14-
sessionToken: process.env.AWS_SESSION_TOKEN,
15-
region: REVALIDATION_QUEUE_REGION,
16-
});
17-
const awsFetch = customFetchClient(awsClient);
10+
const getAwsClient = () => {
11+
if (awsClient) {
12+
return awsClient;
13+
} else {
14+
awsClient = new AwsClient({
15+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
16+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
17+
sessionToken: process.env.AWS_SESSION_TOKEN,
18+
region: process.env.REVALIDATION_QUEUE_REGION,
19+
});
20+
return awsClient;
21+
}
22+
};
23+
24+
const awsFetch = (body: RequestInit["body"]) => {
25+
const { REVALIDATION_QUEUE_REGION } = process.env;
26+
const client = getAwsClient();
27+
return customFetchClient(client)(
28+
`https://sqs.${REVALIDATION_QUEUE_REGION ?? "us-east-1"}.amazonaws.com`,
29+
{
30+
method: "POST",
31+
headers: {
32+
"Content-Type": "application/x-amz-json-1.0",
33+
"X-Amz-Target": "AmazonSQS.SendMessage",
34+
},
35+
body,
36+
},
37+
);
38+
};
1839
const queue: Queue = {
1940
send: async ({ MessageBody, MessageDeduplicationId, MessageGroupId }) => {
2041
try {
42+
const { REVALIDATION_QUEUE_URL } = process.env;
2143
const result = await awsFetch(
22-
`https://sqs.${REVALIDATION_QUEUE_REGION ?? "us-east-1"}.amazonaws.com`,
23-
{
24-
method: "POST",
25-
headers: {
26-
"Content-Type": "application/x-amz-json-1.0",
27-
"X-Amz-Target": "AmazonSQS.SendMessage",
28-
},
29-
body: JSON.stringify({
30-
QueueUrl: REVALIDATION_QUEUE_URL,
31-
MessageBody: JSON.stringify(MessageBody),
32-
MessageDeduplicationId,
33-
MessageGroupId,
34-
}),
35-
},
44+
JSON.stringify({
45+
QueueUrl: REVALIDATION_QUEUE_URL,
46+
MessageBody: JSON.stringify(MessageBody),
47+
MessageDeduplicationId,
48+
MessageGroupId,
49+
}),
3650
);
3751
if (result.status !== 200) {
3852
throw new RecoverableError(`Failed to send message: ${result.status}`);

0 commit comments

Comments
 (0)