ac-lambda-deployment 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +66 -45
- package/package.json +4 -4
package/index.js
CHANGED
|
@@ -114,7 +114,7 @@ class LambdaDeployer {
|
|
|
114
114
|
|
|
115
115
|
const params = {
|
|
116
116
|
FunctionName: config.functionName,
|
|
117
|
-
Runtime: config.runtime || '
|
|
117
|
+
Runtime: config.runtime || 'nodejs22.x',
|
|
118
118
|
Role: config.roleArn,
|
|
119
119
|
Handler: config.handler || 'lambda.handler',
|
|
120
120
|
Code: { ZipFile: zipBuffer },
|
|
@@ -129,26 +129,17 @@ class LambdaDeployer {
|
|
|
129
129
|
return this.lambda.send(command)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
//
|
|
133
|
-
async
|
|
134
|
-
const zipBuffer = fs.readFileSync(zipPath)
|
|
135
|
-
|
|
136
|
-
const params = {
|
|
137
|
-
FunctionName: functionName,
|
|
138
|
-
ZipFile: zipBuffer
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const command = new UpdateFunctionCodeCommand(params)
|
|
142
|
-
|
|
143
|
-
// Retry logic for concurrent updates
|
|
132
|
+
// Generic retry logic for any command
|
|
133
|
+
async updateWithRetry(command, updateType) {
|
|
144
134
|
for (let i = 0; i < 3; i++) {
|
|
145
135
|
try {
|
|
146
|
-
return this.lambda.send(command)
|
|
136
|
+
return await this.lambda.send(command)
|
|
147
137
|
}
|
|
148
138
|
catch (err) {
|
|
149
139
|
if (err.name === 'ResourceConflictException' && i < 2) {
|
|
150
|
-
|
|
151
|
-
|
|
140
|
+
const waitTime = (i + 1) * 30000
|
|
141
|
+
console.log(`Function ${updateType} is being updated, waiting ${waitTime/1000} seconds... (attempt ${i + 1}/3)`)
|
|
142
|
+
await new Promise(resolve => setTimeout(resolve, waitTime))
|
|
152
143
|
continue
|
|
153
144
|
}
|
|
154
145
|
throw err
|
|
@@ -156,34 +147,68 @@ class LambdaDeployer {
|
|
|
156
147
|
}
|
|
157
148
|
}
|
|
158
149
|
|
|
159
|
-
//
|
|
160
|
-
async
|
|
161
|
-
const
|
|
162
|
-
FunctionName: config.functionName,
|
|
163
|
-
Runtime: config.runtime,
|
|
164
|
-
Handler: config.handler,
|
|
165
|
-
Description: config.description,
|
|
166
|
-
Timeout: config.timeout,
|
|
167
|
-
MemorySize: config.memorySize,
|
|
168
|
-
Environment: config.environment ? { Variables: config.environment } : undefined,
|
|
169
|
-
Layers: config.layers || []
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const command = new UpdateFunctionConfigurationCommand(params)
|
|
150
|
+
// Wait until function is in Active state and ready for next update
|
|
151
|
+
async waitForFunctionReady(functionName, maxWaitMs = 120000) {
|
|
152
|
+
const startTime = Date.now()
|
|
173
153
|
|
|
174
|
-
|
|
175
|
-
for (let i = 0; i < 3; i++) {
|
|
154
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
176
155
|
try {
|
|
177
|
-
|
|
156
|
+
const result = await this.lambda.send(new GetFunctionCommand({ FunctionName: functionName }))
|
|
157
|
+
const state = result.Configuration?.State
|
|
158
|
+
const lastUpdateStatus = result.Configuration?.LastUpdateStatus
|
|
159
|
+
|
|
160
|
+
if (state === 'Active' && lastUpdateStatus === 'Successful') {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (lastUpdateStatus === 'Failed') {
|
|
165
|
+
throw new Error('Previous update failed')
|
|
166
|
+
}
|
|
178
167
|
}
|
|
179
168
|
catch (err) {
|
|
180
|
-
if (err.
|
|
181
|
-
|
|
182
|
-
await new Promise(resolve => setTimeout(resolve, 20000))
|
|
183
|
-
continue
|
|
169
|
+
if (err.message === 'Previous update failed') {
|
|
170
|
+
throw err
|
|
184
171
|
}
|
|
185
|
-
|
|
172
|
+
// Ignore other errors during polling
|
|
186
173
|
}
|
|
174
|
+
|
|
175
|
+
await new Promise(resolve => setTimeout(resolve, 3000))
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
throw new Error('Timeout waiting for function to be ready')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Update function code, then config sequentially
|
|
182
|
+
async updateFunctionSequential(functionName, zipPath, config) {
|
|
183
|
+
const zipBuffer = fs.readFileSync(zipPath)
|
|
184
|
+
|
|
185
|
+
// Step 1: Update code
|
|
186
|
+
console.log('Updating function code...')
|
|
187
|
+
const codeParams = {
|
|
188
|
+
FunctionName: functionName,
|
|
189
|
+
ZipFile: zipBuffer
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
await this.updateWithRetry(new UpdateFunctionCodeCommand(codeParams), 'code')
|
|
193
|
+
|
|
194
|
+
// Step 2: Wait for function to be ready, then update configuration
|
|
195
|
+
if (config.layers || config.environment || config.timeout || config.memorySize || config.description) {
|
|
196
|
+
console.log('Waiting for code update to complete...')
|
|
197
|
+
await this.waitForFunctionReady(functionName)
|
|
198
|
+
|
|
199
|
+
const configParams = {
|
|
200
|
+
FunctionName: functionName,
|
|
201
|
+
Runtime: config.runtime || 'nodejs18.x',
|
|
202
|
+
Handler: config.handler || 'lambda.handler',
|
|
203
|
+
Description: config.description,
|
|
204
|
+
Timeout: config.timeout || 30,
|
|
205
|
+
MemorySize: config.memorySize || 128,
|
|
206
|
+
Environment: config.environment ? { Variables: config.environment } : undefined,
|
|
207
|
+
Layers: config.layers || []
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log('Updating function configuration...')
|
|
211
|
+
await this.updateWithRetry(new UpdateFunctionConfigurationCommand(configParams), 'configuration')
|
|
187
212
|
}
|
|
188
213
|
}
|
|
189
214
|
|
|
@@ -279,15 +304,11 @@ class LambdaDeployer {
|
|
|
279
304
|
|
|
280
305
|
if (exists) {
|
|
281
306
|
console.log('Updating existing function...')
|
|
282
|
-
await this.updateFunction(functionName, zipPath)
|
|
283
307
|
|
|
284
|
-
// Update function
|
|
285
|
-
|
|
286
|
-
console.log('Updating function configuration...')
|
|
287
|
-
await this.updateFunctionConfig(config)
|
|
288
|
-
}
|
|
308
|
+
// Update function code and config sequentially
|
|
309
|
+
await this.updateFunctionSequential(functionName, zipPath, config)
|
|
289
310
|
|
|
290
|
-
// Update SQS triggers
|
|
311
|
+
// Update SQS triggers (separate API)
|
|
291
312
|
if (config.sqsTriggers) {
|
|
292
313
|
console.log('Updating SQS triggers...')
|
|
293
314
|
await this.updateEventSourceMappings(functionName, config.sqsTriggers)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ac-lambda-deployment",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Simple AWS Lambda deployment tool using AWS SDK v3",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@aws-sdk/client-lambda": "^3.
|
|
37
|
-
"@aws-sdk/credential-provider-ini": "^3.
|
|
36
|
+
"@aws-sdk/client-lambda": "^3.913.0",
|
|
37
|
+
"@aws-sdk/credential-provider-ini": "^3.913.0",
|
|
38
38
|
"archiver": "^7.0.1"
|
|
39
39
|
},
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=20.0.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"eslint": "^9.
|
|
44
|
+
"eslint": "^9.38.0"
|
|
45
45
|
}
|
|
46
46
|
}
|