lambda-live-debugger 1.12.2 → 1.12.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.
Binary file
@@ -7,6 +7,7 @@ import { Configuration } from './configuration.mjs';
7
7
  import { AwsCredentials } from './awsCredentials.mjs';
8
8
  import { getModuleDirname } from './getDirname.mjs';
9
9
  import { Logger } from './logger.mjs';
10
+ import { runWithConcurrency } from './utils/runWithConcurrency.mjs';
10
11
  import * as crypto from 'crypto';
11
12
  let lambdaClient;
12
13
  let iamClient;
@@ -46,6 +47,9 @@ function getLambdaClient() {
46
47
  profile: Configuration.config.profile,
47
48
  role: Configuration.config.role,
48
49
  }),
50
+ // client-side rate limiting and generous retries to avoid TooManyRequestsException
51
+ retryMode: 'adaptive',
52
+ maxAttempts: 10,
49
53
  });
50
54
  }
51
55
  return lambdaClient;
@@ -63,6 +67,9 @@ function getIAMClient() {
63
67
  profile: Configuration.config.profile,
64
68
  role: Configuration.config.role,
65
69
  }),
70
+ // client-side rate limiting and generous retries to avoid TooManyRequestsException
71
+ retryMode: 'adaptive',
72
+ maxAttempts: 10,
66
73
  });
67
74
  }
68
75
  return iamClient;
@@ -321,10 +328,10 @@ async function applyAddingInfra(changes) {
321
328
  Logger.verbose(`Using existing layer version: ${changes.existingLayerVersionArn}`);
322
329
  layerVersionArn = changes.existingLayerVersionArn;
323
330
  }
324
- const promises = [];
331
+ const tasks = [];
325
332
  // Add LLD to functions
326
333
  for (const lambdaData of changes.lambdasToAdd) {
327
- promises.push(addLayerToLambda({
334
+ tasks.push(() => addLayerToLambda({
328
335
  ...lambdaData,
329
336
  layers: [
330
337
  layerVersionArn,
@@ -335,17 +342,17 @@ async function applyAddingInfra(changes) {
335
342
  }
336
343
  // Remove LLD from filtered functions
337
344
  for (const lambdaData of changes.lambdasToRemove) {
338
- promises.push(removeLayerFromLambda(lambdaData));
345
+ tasks.push(() => removeLayerFromLambda(lambdaData));
339
346
  }
340
347
  // Add policies to roles
341
348
  for (const roleName of changes.rolesToAdd) {
342
- promises.push(addPolicyToRole(roleName));
349
+ tasks.push(() => addPolicyToRole(roleName));
343
350
  }
344
351
  // Remove policies from roles
345
352
  for (const roleName of changes.rolesToRemove) {
346
- promises.push(removePolicyFromLambdaRole(roleName));
353
+ tasks.push(() => removePolicyFromLambdaRole(roleName));
347
354
  }
348
- await Promise.all(promises);
355
+ await runWithConcurrency(tasks);
349
356
  }
350
357
  /**
351
358
  * Get the planned infrastructure changes including removal from filtered functions
@@ -356,29 +363,27 @@ async function getInfraChangesForAdding() {
356
363
  const configLambdasAll = Configuration.getLambdasAll();
357
364
  const configLambdasUpdate = configLambdasAll.filter((l) => !(l.filteredOut === true));
358
365
  const configLambdasRemove = configLambdasAll.filter((l) => l.filteredOut === true);
359
- const lambdasToUpdatePromise = Promise.all(configLambdasUpdate.map(async (func) => {
366
+ const lambdasToUpdatePromise = runWithConcurrency(configLambdasUpdate.map((func) => async () => {
360
367
  const lambdaUpdate = await analyzeLambdaAdd(func.functionName, existingLayer?.LayerVersionArn);
361
368
  return lambdaUpdate;
362
369
  }));
363
- const lambdasToRemovePromise = Promise.all(configLambdasRemove.map(async (func) => {
364
- return analyzeLambdaRemove(func.functionName);
365
- }));
370
+ const lambdasToRemovePromise = runWithConcurrency(configLambdasRemove.map((func) => () => analyzeLambdaRemove(func.functionName)));
366
371
  // Get all role names for lambdas to update, ensure uniqueness, then analyze
367
372
  const roleNamesToAddSet = new Set();
368
- const roleNamesToAddPromise = Promise.all(configLambdasUpdate.map(async (func) => {
373
+ const roleNamesToAddPromise = runWithConcurrency(configLambdasUpdate.map((func) => async () => {
369
374
  const roleName = await getRoleNameFromFunction(func.functionName);
370
375
  roleNamesToAddSet.add(roleName);
371
376
  }));
372
377
  // Get all role names for lambdas to remove, ensure uniqueness, then analyze
373
378
  const roleNamesToRemoveSet = new Set();
374
- const roleNamesToRemovePromise = Promise.all(configLambdasRemove.map(async (func) => {
379
+ const roleNamesToRemovePromise = runWithConcurrency(configLambdasRemove.map((func) => async () => {
375
380
  const roleName = await getRoleNameFromFunction(func.functionName);
376
381
  roleNamesToRemoveSet.add(roleName);
377
382
  }));
378
383
  // Analyze roles to add
379
384
  await roleNamesToAddPromise;
380
385
  const roleNamesToAdd = Array.from(roleNamesToAddSet);
381
- const rolesToAddPromise = Promise.all(roleNamesToAdd.map(async (roleName) => {
386
+ const rolesToAddPromise = runWithConcurrency(roleNamesToAdd.map((roleName) => async () => {
382
387
  const roleUpdate = await analyzeRoleAdd(roleName);
383
388
  return roleUpdate.addPolicy ? roleUpdate.roleName : undefined;
384
389
  }));
@@ -387,7 +392,7 @@ async function getInfraChangesForAdding() {
387
392
  let roleNamesToRemove = Array.from(roleNamesToRemoveSet);
388
393
  // make sure that roles removed are not in the list to add
389
394
  roleNamesToRemove = roleNamesToRemove.filter((role) => !roleNamesToAdd.includes(role));
390
- const rolesToRemovePromise = Promise.all(roleNamesToRemove.map(async (roleName) => {
395
+ const rolesToRemovePromise = runWithConcurrency(roleNamesToRemove.map((roleName) => async () => {
391
396
  const roleRemoval = await analyzeRoleRemove(roleName);
392
397
  return roleRemoval.needToRemovePolicy ? roleRemoval.roleName : undefined;
393
398
  }));
@@ -488,17 +493,15 @@ async function analyzeLambdaRemove(functionName) {
488
493
  async function getInfraChangesForRemoving() {
489
494
  Logger.verbose('Analyzing infrastructure changes for removing Lambda Live Debugger');
490
495
  const allLambdas = Configuration.getLambdasAll();
491
- const lambdasToRemovePromise = Promise.all(allLambdas.map(async (func) => {
492
- return analyzeLambdaRemove(func.functionName);
493
- }));
496
+ const lambdasToRemovePromise = runWithConcurrency(allLambdas.map((func) => () => analyzeLambdaRemove(func.functionName)));
494
497
  // Get all role names for lambdas to remove, ensure uniqueness, then analyze
495
498
  const roleNamesToRemoveSet = new Set();
496
- await Promise.all(allLambdas.map(async (func) => {
499
+ await runWithConcurrency(allLambdas.map((func) => async () => {
497
500
  const roleName = await getRoleNameFromFunction(func.functionName);
498
501
  roleNamesToRemoveSet.add(roleName);
499
502
  }));
500
503
  const roleNamesToRemove = Array.from(roleNamesToRemoveSet);
501
- const rolesToRemovePromise = Promise.all(roleNamesToRemove.map(async (roleName) => {
504
+ const rolesToRemovePromise = runWithConcurrency(roleNamesToRemove.map((roleName) => async () => {
502
505
  const roleRemoval = await analyzeRoleRemove(roleName);
503
506
  return roleRemoval.needToRemovePolicy ? roleRemoval.roleName : undefined;
504
507
  }));
@@ -516,14 +519,14 @@ async function getInfraChangesForRemoving() {
516
519
  */
517
520
  async function applyRemoveInfra(changes) {
518
521
  Logger.verbose('Starting infrastructure removal');
519
- const promises = [];
522
+ const tasks = [];
520
523
  for (const lambdaData of changes.lambdasToRemove) {
521
- promises.push(removeLayerFromLambda(lambdaData));
524
+ tasks.push(() => removeLayerFromLambda(lambdaData));
522
525
  }
523
526
  for (const roleName of changes.rolesToRemove) {
524
- promises.push(removePolicyFromLambdaRole(roleName));
527
+ tasks.push(() => removePolicyFromLambdaRole(roleName));
525
528
  }
526
- await Promise.all(promises);
529
+ await runWithConcurrency(tasks);
527
530
  }
528
531
  /**
529
532
  * Get the Lambda function configuration including layers, environment variables, and timeout
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Run async tasks with a limited number of tasks running concurrently,
3
+ * for example to avoid hitting AWS API rate limits.
4
+ * @param tasks
5
+ * @param limit
6
+ * @returns results in the same order as the tasks
7
+ */
8
+ export declare function runWithConcurrency<T>(tasks: (() => Promise<T>)[], limit?: number): Promise<T[]>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Run async tasks with a limited number of tasks running concurrently,
3
+ * for example to avoid hitting AWS API rate limits.
4
+ * @param tasks
5
+ * @param limit
6
+ * @returns results in the same order as the tasks
7
+ */
8
+ export async function runWithConcurrency(tasks, limit = 5) {
9
+ const results = new Array(tasks.length);
10
+ let nextTaskIndex = 0;
11
+ const workers = Array.from({ length: Math.min(limit, tasks.length) }, async () => {
12
+ while (nextTaskIndex < tasks.length) {
13
+ const taskIndex = nextTaskIndex++;
14
+ results[taskIndex] = await tasks[taskIndex]();
15
+ }
16
+ });
17
+ await Promise.all(workers);
18
+ return results;
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lambda-live-debugger",
3
- "version": "1.12.2",
3
+ "version": "1.12.3",
4
4
  "type": "module",
5
5
  "description": "Debug Lambda functions locally like it is running in the cloud",
6
6
  "repository": {