Skip to content

[Lambda DevX] Bypass Concurrency Settings #11418

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Oct 14, 2024

Conversation

MEPalma
Copy link
Contributor

@MEPalma MEPalma commented Aug 27, 2024

Motivation

Lambda Debug Mode configurations allow users to specify a debug port for each qualified Lambda ARN. This means that as long as lease limits are not exceeded, the system can concurrently evaluate multiple invocations of the same Lambda function version. However, this also means that additional containers might attempt to establish new debugging sessions on the same port. A similar issue can arise when updating provisioned concurrency configurations, which can result in multiple containers being spun up for the same Lambda function version. To enhance the developer experience in debugging Lambda functions, these changes introduces bypass logics for leasing and provisioning multiple instances of the same Lambda function version when it is being debugged.

Changes

  • utility function is_lambda_debug_enabled_for which computed whether the given lambda arn is being debugged
  • check for non concurrent leases in localstack.services.lambda_.invocation.counting_service.CountingService.get_invocation_lease
  • limit true provisioning to 1 environment in localstack.services.lambda_.invocation.assignment.AssignmentService.scale_provisioned_concurrency

Testing

As a testing setup for Lambda Debug Mode is in the works and this feature is in preview, testing is conducted manually. Here follow scenarios relevant for these changes.

Test for Concurrent Invocations

  1. Start Lambda Debug Mode with config:

    functions:
      arn:aws:lambda:eu-central-1:000000000000:function:handler_1-handler_1:
        debug-port: 19891
  2. deploy lambda functions handler_1-handler_1 :

       DEBUGGER_ENDPOINT = "0.0.0.0"
       DEBUGGER_PORT = 19891
       
       def handler_1(event, context):
           """Lambda handler that will get invoked by the LocalStack runtime"""
       
           # wait for the debugger to get attached
           import debugpy
           debugpy.listen((DEBUGGER_ENDPOINT, DEBUGGER_PORT))
           debugpy.wait_for_client()  # blocks execution until client is attached
       
           # print the incoming invocation event
           print(event)
           return {"body": "Hello from handler_1"}
  3. Send a first invoke for handler_1-handler_1

  4. Send a second invoke (on another thread) for handler_1-handler_1

  5. Assert that in the console the warning message Concurrent lambda invocations disabled for 'arn:aws:lambda:eu-central-1:000000000000:function:handler_1-handler_1:$LATEST' by Lambda Debug Mode for the second invocation, whilst the first one can continue to be debugged as usual by connecting to 19891

  6. Assert only one container for the lambda version was created

  7. If the tool used to forward the invocation requests implements a periodic retry (such as boto) then the above error message would show up every time the request is received

Test for Provisioning

  1. Start Lambda Debug Mode with config (note we are defining the qualifier for version 1 in this configuration, that means that arn:aws:lambda:eu-central-1:000000000000:function:handler_1-handler_1, which is equal to arn:aws:lambda:eu-central-1:000000000000:function:handler_1-handler_1$LATEST will not be affected by Lambda Debug Mode in any way):

    functions:
      arn:aws:lambda:eu-central-1:000000000000:function:handler_1-handler_1:1:
        debug-port: 19891
  2. deploy lambda functions handler_1-handler_1 :

       DEBUGGER_ENDPOINT = "0.0.0.0"
       DEBUGGER_PORT = 19891
       
       def handler_1(event, context):
           """Lambda handler that will get invoked by the LocalStack runtime"""
       
           # wait for the debugger to get attached
           import debugpy
           debugpy.listen((DEBUGGER_ENDPOINT, DEBUGGER_PORT))
           debugpy.wait_for_client()  # blocks execution until client is attached
       
           # print the incoming invocation event
           print(event)
           return {"body": "Hello from handler_1"}
  3. create a version for the lambda function: awslocal lambda publish-version --function-name handler_1-handler_1

  4. request provisioning for more than one instance:

     awslocal lambda put-provisioned-concurrency-config \
       --function-name handler_1-handler_1 \
       --qualifier 1\
       --provisioned-concurrent-executions 30
  5. assert in the console the following warning is logged: Environments for 'arn:aws:lambda:eu-central-1:000000000000:function:handler_1-handler_1:1' enforced to '1' by Lambda Debug Mode, configurations will continue to report the set value '30'

  6. assert only one container for the lambda version is created

  7. Send a first invoke for handler_1-handler_1:1

  8. Send a second invoke (on another thread) for handler_1-handler_1:1

  9. Assert only one container for the lambda version was created

  10. Assert that in the console the warning message Concurrent lambda invocations disabled for 'arn:aws:lambda:eu-central-1:000000000000:function:handler_1-handler_1:1' by Lambda Debug Mode for the second invocation, whilst the first one can continue to be debugged as usual by connecting to 19891

@MEPalma MEPalma added the semver: minor Non-breaking changes which can be included in minor releases, but not in patch releases label Aug 27, 2024
@MEPalma MEPalma added this to the 3.7 milestone Aug 27, 2024
@MEPalma MEPalma self-assigned this Aug 27, 2024
Copy link

S3 Image Test Results (AMD64 / ARM64)

  2 files    2 suites   3m 28s ⏱️
420 tests 368 ✅  52 💤 0 ❌
840 runs  736 ✅ 104 💤 0 ❌

Results for commit 58e684b.

Copy link

github-actions bot commented Aug 27, 2024

LocalStack Community integration with Pro

    2 files  ±0      2 suites  ±0   1h 39m 1s ⏱️ - 1m 28s
3 492 tests ±0  3 079 ✅ ±0  413 💤 ±0  0 ❌ ±0 
3 494 runs  ±0  3 079 ✅ ±0  415 💤 ±0  0 ❌ ±0 

Results for commit 66e5532. ± Comparison against base commit 67f5698.

♻️ This comment has been updated with latest results.

@MEPalma MEPalma modified the milestones: 3.7, 3.8 Aug 28, 2024
Copy link
Member

@dfangl dfangl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a sensible addition, LGTM!

@@ -125,6 +128,24 @@ def get_invocation_lease(
unqualified_function_arn = function_version.id.unqualified_arn()
qualified_arn = function_version.id.qualified_arn()

# Enforce one lease per ARN if the global flag is set
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What global flag should be set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LDM flag and in the LDM config we have settings for this qualified arn, hence the if is_lambda_debug_enabled_for(qualified_arn)

@MEPalma MEPalma modified the milestones: 3.8, 4.0 Oct 1, 2024
@MEPalma MEPalma requested a review from gregfurman as a code owner October 10, 2024 19:58
@MEPalma MEPalma merged commit 13d85d1 into master Oct 14, 2024
34 checks passed
@MEPalma MEPalma deleted the MEP-LambdaDevX-enforce_concurr_values branch October 14, 2024 07:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver: minor Non-breaking changes which can be included in minor releases, but not in patch releases
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants