X Tutup
Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.

Lambda: fix store typing for serialization#13707

Merged
bentsku merged 4 commits intomainfrom
avro-lambda-store
Feb 10, 2026
Merged

Lambda: fix store typing for serialization#13707
bentsku merged 4 commits intomainfrom
avro-lambda-store

Conversation

@bentsku
Copy link
Contributor

@bentsku bentsku commented Feb 5, 2026

Motivation

This PR improves Lambda typing to support more serialization frameworks.

Changes

  • update VersionFunctionConfiguration to use the proper casing for CapacityProviderConfig: the TODO that was there was because the code was overriding the TypeDict definition as it was already declared in the scope 😬 also updated all usage of this attribute
  • make a lot of field have the proper type hint of None Union because it gets values straight from the provider requests, and those values can be None (caught by the serialization framework with real values)
  • use subclass for code: serialization framework does not support parent class type hint / polymorphism
  • move the instance_id hack in the on_after_state_load logic as we're already iterating over all Function to avoid putting this on the serialization framework

Tests

Related

Done ✅ #13702 is also adding changes related to CapacityProviderConfig which still uses the wrong casing, rebase if it gets merged before 👍

@bentsku bentsku added this to the 4.14 milestone Feb 5, 2026
@bentsku bentsku self-assigned this Feb 5, 2026
@bentsku bentsku added aws:lambda AWS Lambda semver: patch Non-breaking changes which can be included in patch releases semver: minor Non-breaking changes which can be included in minor releases, but not in patch releases docs: skip Pull request does not require documentation changes notes: skip Pull request does not have to be mentioned in the release notes and removed semver: patch Non-breaking changes which can be included in patch releases labels Feb 5, 2026
@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Test Results - Preflight, Unit

23 114 tests  ±0   21 255 ✅ ±0   6m 17s ⏱️ ±0s
     1 suites ±0    1 859 💤 ±0 
     1 files   ±0        0 ❌ ±0 

Results for commit 2ace1c8. ± Comparison against base commit 4f689f3.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Test Results (amd64) - Acceptance

7 tests  ±0   5 ✅ ±0   3m 3s ⏱️ -1s
1 suites ±0   2 💤 ±0 
1 files   ±0   0 ❌ ±0 

Results for commit 2ace1c8. ± Comparison against base commit 4f689f3.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Test Results (amd64) - Integration, Bootstrap

    5 files      5 suites   2h 0m 35s ⏱️
3 786 tests 3 548 ✅ 238 💤 0 ❌
3 792 runs  3 548 ✅ 244 💤 0 ❌

Results for commit 2ace1c8.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

LocalStack Community integration with Pro

    2 files  ±    0      2 suites  ±0   1h 29m 21s ⏱️ - 27m 57s
3 762 tests  - 1 436  3 520 ✅  - 1 327  242 💤  - 109  0 ❌ ±0 
3 764 runs   - 1 436  3 520 ✅  - 1 327  244 💤  - 109  0 ❌ ±0 

Results for commit 2ace1c8. ± Comparison against base commit 4f689f3.

This pull request removes 1436 tests.
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_lambda_dynamodb
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_opensearch_crud
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_search_books
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_setup
tests.aws.scenario.kinesis_firehose.test_kinesis_firehose.TestKinesisFirehoseScenario ‑ test_kinesis_firehose_s3
tests.aws.scenario.lambda_destination.test_lambda_destination_scenario.TestLambdaDestinationScenario ‑ test_destination_sns
tests.aws.scenario.lambda_destination.test_lambda_destination_scenario.TestLambdaDestinationScenario ‑ test_infra
tests.aws.scenario.loan_broker.test_loan_broker.TestLoanBrokerScenario ‑ test_prefill_dynamodb_table
tests.aws.scenario.loan_broker.test_loan_broker.TestLoanBrokerScenario ‑ test_stepfunctions_input_recipient_list[step_function_input0-SUCCEEDED]
tests.aws.scenario.loan_broker.test_loan_broker.TestLoanBrokerScenario ‑ test_stepfunctions_input_recipient_list[step_function_input1-SUCCEEDED]
…

♻️ This comment has been updated with latest results.

@bentsku bentsku marked this pull request as ready for review February 6, 2026 10:54
Copy link
Member

@joe4dev joe4dev left a comment

Choose a reason for hiding this comment

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

Thank you for pushing Lambda towards Avro Persistence 🚀

My main concern is regarding the HACK of serializing the volatile instance_id (see comment). I would like to hear @dfangl's thoughts on that one.

working_directory: str
command: list[str] = dataclasses.field(default_factory=list)
entrypoint: list[str] = dataclasses.field(default_factory=list)
working_directory: str | None
Copy link
Member

Choose a reason for hiding this comment

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

Good catch. Absolutely right that these can be None given the value is taken from the request via .get() here.

@dfangl Was the goal with the non-None types here to enforce providing a default case, or did we miss this?

Copy link
Member

Choose a reason for hiding this comment

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

I think we missed it. None values probably make sense here, as they connote a special meaning (it's not overridden to be empty, it's just not specified), in comparison to an empty list.

license_info: str
compatible_runtimes: list[Runtime]
compatible_architectures: list[Architecture]
# we need to use Union types as inheritance is not supported by serialization framework
Copy link
Member

Choose a reason for hiding this comment

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

praise: Thanks for the clarifying comment. Good to know.

# A LocalStack restart or persistence load should create a new instance id.
# Used for retaining invoke queues across version updates for $LATEST, but
# separate unrelated instances.
fn.instance_id = short_uid()
Copy link
Member

Choose a reason for hiding this comment

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

I am a little concerned that storing the ephemeral and internal instance_id in the model violates the assumption:

The instance id MUST be unique to the function and a given LocalStack instance

While this on_after_state_load approach fixes uniqueness for persistence loading, I wonder what happens when loading a CloudPod 🤔 . Does the instance_id get fixed there?

There might be a (small) chance to re-create the ugly race condition fixed in #10831 when deleting a function immediately followed by loading that same function from a CloudPod. wdyt @dfangl

Copy link
Member

Choose a reason for hiding this comment

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

What alternatives do we have?

  • Remove instance_id from the models and store it in the service (discussed here)
  • Ensure loading a Pod/State containing a Lambda function resets the instance_id
  • Offer some kind of @ignore annotation to skip serialization for volatile fields
  • 🤞
  • ...

Copy link
Contributor Author

@bentsku bentsku Feb 6, 2026

Choose a reason for hiding this comment

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

Loading a Cloud Pod also triggers this hook 👍 so I don’t think this would be an issue? Except if we merge state, like restoring only functions in a specific account, but I don’t think this has been implemented yet, and the current logic would probably fail anyway?

if this is really an issue, I can try to write custom code to create a special class that would change value every time it’s restored, but that feels like abusing the system. Having the attribute somewhere else would be better

Copy link
Member

Choose a reason for hiding this comment

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

I think it makes sense to leave it here, we do not support partial state loads anyway I think, and will always reload everything.
We have to keep in mind that the instance id now ends up in the state and gets overridden at load - my only fear is that it will bite us at some point if we forget about resetting it.

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.

Thanks for tackling this! My only concern is the instance_id and what happens if we don't properly reset it after restoration, but for now this seems fine.

working_directory: str
command: list[str] = dataclasses.field(default_factory=list)
entrypoint: list[str] = dataclasses.field(default_factory=list)
working_directory: str | None
Copy link
Member

Choose a reason for hiding this comment

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

I think we missed it. None values probably make sense here, as they connote a special meaning (it's not overridden to be empty, it's just not specified), in comparison to an empty list.

# A LocalStack restart or persistence load should create a new instance id.
# Used for retaining invoke queues across version updates for $LATEST, but
# separate unrelated instances.
fn.instance_id = short_uid()
Copy link
Member

Choose a reason for hiding this comment

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

I think it makes sense to leave it here, we do not support partial state loads anyway I think, and will always reload everything.
We have to keep in mind that the instance id now ends up in the state and gets overridden at load - my only fear is that it will bite us at some point if we forget about resetting it.

@bentsku
Copy link
Contributor Author

bentsku commented Feb 10, 2026

My only concern is the instance_id and what happens if we don't properly reset it after restoration, but for now this seems fine.

Agreed, I think it would make sense for this field to be a "runtime variable" and having it live in some kind of global object outside the state, that would probably simplify things a bit?

Thanks a lot for your reviews 🙏

@dfangl
Copy link
Member

dfangl commented Feb 10, 2026

Agreed, I think it would make sense for this field to be a "runtime variable" and having it live in some kind of global object outside the state, that would probably simplify things a bit?

Maybe, let's keep this in mind, but I would not change it in this PR honestly, we might not catch all implications, and this should make it in!

@bentsku bentsku merged commit f974d16 into main Feb 10, 2026
41 checks passed
@bentsku bentsku deleted the avro-lambda-store branch February 10, 2026 19:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

aws:lambda AWS Lambda docs: skip Pull request does not require documentation changes notes: skip Pull request does not have to be mentioned in the release notes 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.

3 participants

X Tutup