Skip to content

feat(host): add ILambdaLifecycleContext for lifecycle handlers#252

Merged
j-d-ha merged 27 commits into
mainfrom
feature/#236-add-ILambdaOnInitContext-for-OnInit-handlers
Dec 17, 2025
Merged

feat(host): add ILambdaLifecycleContext for lifecycle handlers#252
j-d-ha merged 27 commits into
mainfrom
feature/#236-add-ILambdaOnInitContext-for-OnInit-handlers

Conversation

@j-d-ha

@j-d-ha j-d-ha commented Dec 17, 2025

Copy link
Copy Markdown
Collaborator

🚀 Pull Request

📋 Summary

This PR introduces ILambdaLifecycleContext to provide rich context and dependency injection capabilities for OnInit and OnShutdown lifecycle handlers. This replaces the previous (IServiceProvider, CancellationToken) delegate pattern with a more extensible, source-generated DI approach that mirrors the invocation handler pattern.

Key Changes

1. New ILambdaLifecycleContext Interface

  • Provides AWS environment metadata (function name, region, memory, initialization type, etc.)
  • Includes a thread-safe Properties dictionary for sharing state between handlers
  • Exposes scoped ServiceProvider and CancellationToken
  • Located in MinimalLambda.Abstractions for broad accessibility

2. Updated Handler Signatures

// Before
lambda.OnInit(async (IServiceProvider services, CancellationToken ct) => { ... });

// After - Direct DI (recommended)
lambda.OnInit(async (ICache cache, ILogger logger, CancellationToken ct) => { ... });

// After - With context for AWS metadata
lambda.OnInit(async (ILambdaLifecycleContext context, ICache cache) => { ... });

3. Source-Generated Dependency Injection

  • OnInit and OnShutdown handlers now support the same DI patterns as invocation handlers
  • Direct service injection without manual IServiceProvider resolution
  • Keyed services via [FromKeyedServices("key")] attribute
  • Mixed patterns combining context and services

4. Comprehensive Documentation

  • Updated lifecycle management guide with ILambdaLifecycleContext usage patterns
  • Enhanced dependency injection guide with lifecycle handler examples
  • Added context access section to core concepts
  • Documented all 13 context properties with descriptions

5. Extensive Test Coverage

  • Added unit tests for ILambdaLifecycleContext and factory
  • Updated all lifecycle handler tests to use new signatures
  • Source generator snapshot tests updated

✅ Checklist

  • My changes build cleanly
  • I've added/updated relevant tests
  • I've added/updated documentation or README
  • I've followed the coding style for this project
  • I've tested the changes locally (if applicable)

🧪 Related Issues or PRs

Closes #236


💬 Notes for Reviewers

Breaking Changes

This is a breaking change for existing OnInit/OnShutdown handlers:

  • Handler signatures changed from (IServiceProvider, CancellationToken) to source-generated DI
  • Migration is straightforward: replace services.GetRequiredService<T>() with direct parameter injection

Key Files to Review

Core Implementation:

  • src/MinimalLambda.Abstractions/Core/ILambdaLifecycleContext.cs - New interface definition
  • src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs - Implementation with AWS env var reading
  • src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs - Factory for creating contexts

Builder Updates:

  • src/MinimalLambda/Builder/LambdaOnInitBuilder.cs - Updated to use context factory
  • src/MinimalLambda/Builder/LambdaOnShutdownBuilder.cs - Updated to use context factory
  • Both builders now expose Properties dictionary for state sharing

Source Generators:

  • src/MinimalLambda.SourceGenerators/SyntaxProviders/OnInitSyntaxProvider.cs
  • src/MinimalLambda.SourceGenerators/SyntaxProviders/OnShutdownSyntaxProvider.cs
  • Updated to support ILambdaLifecycleContext and new parameter sources

Documentation:

  • docs/guides/lifecycle-management.md - Comprehensive guide with examples
  • docs/guides/dependency-injection.md - DI patterns for lifecycle handlers
  • docs/getting-started/core-concepts.md - Introductory overview

AWS Environment Properties

All AWS environment metadata is read from standard Lambda environment variables:

  • Nullable types used because not all variables are available in all scenarios (e.g., SnapStart)
  • Properties are read lazily on first access
  • Thread-safe implementation for concurrent handler execution

Properties Dictionary

The Properties dictionary enables:

  • Data sharing between OnInit handlers (runs concurrently)
  • Passing initialization data to invocation handlers via ILambdaHostContext.Properties
  • Thread-safe ConcurrentDictionary backing

Migration Path

Existing code using old pattern:

lambda.OnInit(async (IServiceProvider services, CancellationToken ct) =>
{
    var cache = services.GetRequiredService<ICache>();
    await cache.WarmUpAsync(ct);
    return true;
});

Migrates to:

lambda.OnInit(async (ICache cache, CancellationToken ct) =>
{
    await cache.WarmUpAsync(ct);
    return true;
});

For advanced scenarios needing AWS metadata:

lambda.OnInit(async (ILambdaLifecycleContext context, ICache cache) =>
{
    var logger = context.ServiceProvider.GetRequiredService<ILogger<Program>>();
    logger.LogInformation("Init type: {Type}, Memory: {MB}MB", 
        context.InitializationType, context.FunctionMemorySize);
    await cache.WarmUpAsync(context.CancellationToken);
    return true;
});

…fetime

- Introduced `LifetimeStopwatch` class to monitor elapsed time since application start.
- Registered `LifetimeStopwatch` as a singleton in `LambdaApplicationBuilder`.
…bda lifecycle management

- Introduced `ILambdaLifecycleContext` to encapsulate Lambda lifecycle event information such as initialization and shutdown.
- Added properties like `CancellationToken`, `ElapsedTime`, `FunctionName`, `Region`, and other environment-specific details.
- Intended to provide shared context for Lambda handlers.
- Added `LambdaLifecycleContext` class implementing `ILambdaLifecycleContext` for shared lifecycle context.
- Introduced `LambdaLifecycleContextFactory` for creating `LambdaLifecycleContext` instances.
- Updated `LambdaLifecycleContext` to include core Lambda environment details and integrate with DI.
- Includes disposal logic to properly manage resources like `IServiceScope`.
- Added tests for `LambdaLifecycleContextFactory` to verify factory behavior and property resolution.
- Added tests for `LambdaLifecycleContext` to confirm lazy initialization, property access, and resource disposal.
- Validated configuration-based property initialization for Lambda environment variables.
- Ensured context reusability and correctness across multiple calls.
…ycle context support

- Replaced `LambdaInitDelegate` with `LambdaInitDelegate2` to incorporate `ILambdaLifecycleContext`.
- Added `ILambdaLifecycleContextFactory` and `ConcurrentDictionary` for init handler shared state.
- Updated `DefaultLambdaOnInitBuilderFactory` and `LambdaOnInitBuilder` to support the new context.
- Removed obsolete `OnInitClearLambdaOutputFormatting` method for cleanup and modernization.
- Enhanced init handler building logic with context-aware execution.
…matting

- Renamed `ParameterSource.Context` to `ParameterSource.HostContext` for improved clarity.
- Added new `ParameterSource.LifecycleContext` and support for `ILambdaLifecycleContext`.
- Introduced `OutputFormattingLambdaApplicationExtensions.OnInitClearLambdaOutputFormatting` for custom formatting.
- Updated generators and handlers to improve usage of `HostContext` and `LifecycleContext`.
- Enhanced DI for services, ensuring proper keyed and optional service resolution.
- Improved error handling and timeout behavior during `OnInit` execution.
- Updated `LifetimeStopwatch` to initialize automatically with application start.
- Replaced `BuildHandlerSignature` with a new `BuildHandlerCastCall` method for improved clarity.
- Updated `GenericHandler.scriban` to adapt to the new handler cast generation process.
- Added a new `Cast<T>` helper method for safer and more explicit casting of delegate handlers.
- Enhanced `BuildHandlerCastCall` to generate handler cast calls with detailed parameter and type info.
- Updated `OnInit` lambda argument to allow `IService? y` defaulting to `null` in unit tests.
…cycleContext`

- Updated `OnInit` handler methods to replace `IServiceProvider` with `ILambdaLifecycleContext` parameter.
- Updated `GenericHandler.scriban` to leverage lifecycle context for service resolution.
- Introduced `Cast<T>` helper for safer and more explicit delegate casting across handlers.
- Enhanced generated code to improve readability and maintainability by abstracting casting logic.
- Adjusted unit tests to align with new `ILambdaLifecycleContext` usage and verify correctness.
…leContext`

- Replaced `IServiceProvider` and `CancellationToken` parameters in `LambdaInitDelegate` with `ILambdaLifecycleContext`.
- Simplified `LambdaInitDelegate` definition for improved usage consistency during the Function Init phase.
…nitDelegate`

- Standardized usage of `LambdaInitDelegate` across initialization handlers.
- Updated `ILambdaOnInitBuilder`, `LambdaOnInitBuilder`, and `LambdaApplication` implementation.
- Simplified init handler logic for consistency and easier maintenance.
…ecycle services

- Added `ILifetimeStopwatch` interface to abstract lifetime tracking functionality.
- Updated `LifetimeStopwatch` to implement `ILifetimeStopwatch` for consistency and extensibility.
- Replaced direct `LifetimeStopwatch` references with `ILifetimeStopwatch` in lifecycle services and factories.
- Registered `ILifetimeStopwatch` as a singleton in relevant DI configurations.
- Refactored test cases to align with the interface abstraction and validate the updated behavior.
…ApplicationBuilder`

- Replaced manual host configuration with `LambdaApplicationBuilder` for cleaner test setups.
- Updated related test files to utilize `LambdaApplicationBuilder` for creating hosts.
…eContext` and shared state

- Updated `LambdaShutdownDelegate` to use `ILambdaLifecycleContext`, replacing `IServiceProvider` and `CancellationToken`.
- Added `Properties` dictionary to `ILambdaOnShutdownBuilder` for shared state between handlers.
- Unified `Properties` documentation between `ILambdaOnInitBuilder` and `ILambdaOnShutdownBuilder`.
…ogging and handler simplicity

- Replaced `Console.WriteLine` with `ILogger` for better logging flexibility in `OnInit`.
- Simplified `OnInit` handler signature, removing `IServiceCollection` from unused parameters.
- Refactored `OnShutdown` to streamline the handler and remove unnecessary parameters.
…hared properties support

- Added `ILambdaLifecycleContextFactory` to `LambdaOnShutdownBuilder` for creating lifecycle contexts.
- Integrated `Properties` dictionary to enable shared state management between shutdown handlers.
- Updated `LambdaShutdownDelegate` to use lifecycle context for improved consistency with `OnInit`.
- Modified `DefaultLambdaOnShutdownBuilderFactory` to support context factory injection.
- Refactored `OnShutdown` handlers to simplify parameter usage by removing unused lambda arguments.
- Added `MinimalLambda.SourceGenerators` as an analyzer and updated project references for extended functionality.
…ILambdaLifecycleContext`

- Replaced `IServiceProvider` and `CancellationToken` with `ILambdaLifecycleContext` in `OnShutdown`.
- Streamlined syntax matching for improved consistency and maintainability.
- Simplified test setups by removing redundant `IServiceProvider` and `IServiceScopeFactory` parameters.
- Updated `LambdaShutdownDelegate` usage to align with recent changes, replacing unused lambda arguments.
- Converted constructors and Fact-based test methods to enhanced Theory-based design for improved flexibility.
…ctory tests

- Updated `DefaultLambdaOnShutdownBuilderFactoryTests` to include `ILambdaLifecycleContextFactory`.
- Added validation for null `ILambdaLifecycleContextFactory` in test cases.
- Refactored test setups to accommodate the new context factory parameter in the factory constructor.
…down tests

- Removed unused lambda arguments in `LambdaShutdownDelegate` across test cases.
- Updated test cases for improved readability and reduced redundancy in lambda signatures.
…legate` in tests

- Simplified `LambdaShutdownDelegate` usage by removing unused lambda arguments across test cases.
- Updated test cases to improve readability and align with streamlined delegate signatures.
…leContext` in tests

- Updated shutdown handler tests to use `ILambdaLifecycleContext` instead of `IServiceProvider`.
- Refactored mocked contexts and removed direct `CancellationToken` assignments from test cases.
- Improved consistency with recent changes to `LambdaShutdownDelegate`.
- Replaced `IServiceProvider` and `CancellationToken` usage with `ILambdaLifecycleContext` in test cases.
- Simplified lambda signature in shutdown handler to improve consistency with recent changes.
…plates

- Removed `// Location: ...` comments from `GenericHandler.scriban` and `MapHandler.scriban`.
- Simplified template files by eliminating unnecessary inline documentation.
…down builders

- Integrated `Properties` dictionary into `ILambdaOnInitBuilder` and `ILambdaOnShutdownBuilder`.
- Enabled propagation of shared properties between lifecycle handlers during Init and Shutdown.
- Updated lifecycle management guide to include `ILambdaLifecycleContext` usage and DI patterns.
- Added examples for direct DI, AWS metadata access, state sharing, and keyed services in OnInit handlers.
- Enhanced dependency injection guide with source-generated DI support for OnInit and OnShutdown.
- Expanded core concepts with lifecycle context access patterns and practical usage scenarios.
@github-actions github-actions Bot added breaking-change Introduces a breaking change type: feat New feature labels Dec 17, 2025
@j-d-ha
j-d-ha enabled auto-merge (squash) December 17, 2025 01:22
@sonarqubecloud

Copy link
Copy Markdown

@j-d-ha
j-d-ha merged commit 667327c into main Dec 17, 2025
7 checks passed
@j-d-ha
j-d-ha deleted the feature/#236-add-ILambdaOnInitContext-for-OnInit-handlers branch December 17, 2025 01:23
@codecov

codecov Bot commented Dec 17, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.85714% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../MinimalLambda/Builder/LambdaApplicationBuilder.cs 33.33% 2 Missing and 2 partials ⚠️
src/MinimalLambda/Builder/LambdaOnInitBuilder.cs 81.81% 4 Missing ⚠️
...nerators/OutputGenerators/GenericHandlerSources.cs 70.00% 1 Missing and 2 partials ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #252      +/-   ##
==========================================
+ Coverage   88.23%   88.37%   +0.13%     
==========================================
  Files         127      130       +3     
  Lines        2993     3115     +122     
  Branches      337      344       +7     
==========================================
+ Hits         2641     2753     +112     
- Misses        219      229      +10     
  Partials      133      133              
Files with missing lines Coverage Δ
...OpenTelemetry/OnShutdownOpenTelemetryExtensions.cs 100.00% <100.00%> (ø)
...rceGenerators/Extensions/DelegateInfoExtensions.cs 100.00% <100.00%> (ø)
...malLambda.SourceGenerators/Models/ParameterInfo.cs 97.87% <100.00%> (+2.22%) ⬆️
...ceGenerators/OutputGenerators/MapHandlerSources.cs 97.93% <100.00%> (ø)
...Generators/SyntaxProviders/OnInitSyntaxProvider.cs 100.00% <100.00%> (ø)
...rators/SyntaxProviders/OnShutdownSyntaxProvider.cs 100.00% <100.00%> (ø)
...ambda/Builder/DefaultLambdaOnInitBuilderFactory.cs 100.00% <100.00%> (ø)
...a/Builder/DefaultLambdaOnShutdownBuilderFactory.cs 100.00% <100.00%> (ø)
.../Builder/Extensions/ServiceCollectionExtensions.cs 100.00% <100.00%> (ø)
src/MinimalLambda/Builder/LambdaApplication.cs 97.61% <100.00%> (+0.11%) ⬆️
... and 9 more

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 80eaff3...e6894de. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Introduces a breaking change type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(host): add ILambdaOnInitContext for OnInit handlers

1 participant