@aws/nx-plugin 0.79.1 → 0.80.1

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.
@@ -4,18 +4,19 @@ exports[`fastapi project generator > should match snapshot > main-snapshot 1`] =
4
4
  {
5
5
  "apps/test_api/proj_test_api/__init__.py": """"Automatically generated by Nx."""
6
6
  ",
7
- "apps/test_api/proj_test_api/init.py": "import os
7
+ "apps/test_api/proj_test_api/init.py": "import json
8
+ import os
8
9
  import uuid
9
- from collections.abc import Callable
10
+ from collections.abc import AsyncIterator, Callable
11
+ from typing import Any
10
12
  from urllib.parse import urlparse
11
13
 
12
14
  from aws_lambda_powertools import Logger, Metrics, Tracer
13
15
  from aws_lambda_powertools.metrics import MetricUnit
14
16
  from fastapi import FastAPI, Request, Response
15
17
  from fastapi.openapi.utils import get_openapi
16
- from fastapi.responses import JSONResponse
18
+ from fastapi.responses import JSONResponse, StreamingResponse
17
19
  from fastapi.routing import APIRoute
18
- from mangum import Mangum
19
20
  from pydantic import BaseModel
20
21
  from starlette.middleware.exceptions import ExceptionMiddleware
21
22
 
@@ -31,16 +32,54 @@ class InternalServerErrorDetails(BaseModel):
31
32
  detail: str
32
33
 
33
34
 
34
- app = FastAPI(title="TestApi", responses={500: {"model": InternalServerErrorDetails}})
35
- lambda_handler = Mangum(app)
35
+ class JsonStreamingResponse(StreamingResponse):
36
+ """A streaming response that serializes items to JSON Lines format."""
37
+
38
+ media_type = "application/jsonl"
39
+
40
+ def __init__(
41
+ self,
42
+ content: AsyncIterator[BaseModel],
43
+ status_code: int = 200,
44
+ headers: dict[str, str] | None = None,
45
+ **kwargs: Any,
46
+ ) -> None:
47
+ """Stream json lines from an async iterator yielding Pydantic models"""
48
+ super().__init__(
49
+ content=self._serialize(content),
50
+ status_code=status_code,
51
+ headers=headers,
52
+ media_type=self.media_type,
53
+ **kwargs,
54
+ )
55
+
56
+ @staticmethod
57
+ async def _serialize(
58
+ content: AsyncIterator[BaseModel],
59
+ ) -> AsyncIterator[bytes]:
60
+ """Serialize Pydantic models to JSON Lines format."""
61
+ async for item in content:
62
+ yield (item.model_dump_json() + "\\n").encode("utf-8")
63
+
64
+ @staticmethod
65
+ def openapi_response(
66
+ item_model: type[BaseModel],
67
+ description: str = "Streaming response",
68
+ ) -> dict[str, Any]:
69
+ """Generate an OpenAPI application/jsonl response for a stream of the given model"""
70
+ return {
71
+ "description": description,
72
+ "content": {
73
+ "application/jsonl": {
74
+ "itemSchema": {"$ref": f"#/components/schemas/{item_model.__name__}"},
75
+ }
76
+ },
77
+ # Include the model so FastAPI registers the schema in components/schemas
78
+ "model": item_model,
79
+ }
36
80
 
37
- # Add tracing
38
- lambda_handler.__name__ = "handler" # tracer requires __name__ to be set
39
- lambda_handler = tracer.capture_lambda_handler(lambda_handler)
40
- # Add logging
41
- lambda_handler = logger.inject_lambda_context(lambda_handler, clear_state=True)
42
- # Add metrics last to properly flush metrics.
43
- lambda_handler = metrics.log_metrics(lambda_handler, capture_cold_start_metric=True)
81
+
82
+ app = FastAPI(title="TestApi", responses={500: {"model": InternalServerErrorDetails}})
44
83
 
45
84
 
46
85
  # Add cors middleware
@@ -98,10 +137,16 @@ async def metrics_handler(request: Request, call_next):
98
137
  async def add_correlation_id(request: Request, call_next):
99
138
  # Get correlation id from X-Correlation-Id header
100
139
  corr_id = request.headers.get("x-correlation-id")
101
- if not corr_id and "aws.context" in request.scope:
102
- # If empty, use request id from aws context
103
- corr_id = request.scope["aws.context"].aws_request_id
104
- elif not corr_id:
140
+ if not corr_id:
141
+ # Try to get request id from Lambda context (forwarded by Lambda Web Adapter)
142
+ lambda_context_header = request.headers.get("x-amzn-lambda-context")
143
+ if lambda_context_header:
144
+ try:
145
+ lambda_context = json.loads(lambda_context_header)
146
+ corr_id = lambda_context.get("request_id")
147
+ except (json.JSONDecodeError, KeyError):
148
+ pass
149
+ if not corr_id:
105
150
  # If still empty, use uuid
106
151
  corr_id = uuid.uuid4().hex
107
152
 
@@ -156,11 +201,10 @@ def custom_openapi():
156
201
 
157
202
  app.openapi = custom_openapi
158
203
  ",
159
- "apps/test_api/proj_test_api/main.py": "from pydantic import BaseModel
160
-
161
- from .init import app, lambda_handler, tracer
204
+ "apps/test_api/proj_test_api/main.py": "import uvicorn
205
+ from pydantic import BaseModel
162
206
 
163
- handler = lambda_handler
207
+ from .init import app, tracer
164
208
 
165
209
 
166
210
  class EchoOutput(BaseModel):
@@ -171,6 +215,10 @@ class EchoOutput(BaseModel):
171
215
  @tracer.capture_method
172
216
  def echo(message: str) -> EchoOutput:
173
217
  return EchoOutput(message=f"{message}")
218
+
219
+
220
+ if __name__ == "__main__":
221
+ uvicorn.run("proj_test_api.main:app", port=8000)
174
222
  ",
175
223
  "apps/test_api/scripts/generate_open_api.py": "from proj_test_api.main import app
176
224
  import json, os, sys
@@ -342,8 +390,10 @@ import {
342
390
  Function,
343
391
  FunctionProps,
344
392
  Tracing,
393
+ LayerVersion,
394
+ SnapStartConf,
345
395
  } from 'aws-cdk-lib/aws-lambda';
346
- import { Duration } from 'aws-cdk-lib';
396
+ import { Duration, Stack } from 'aws-cdk-lib';
347
397
  import { CorsHttpMethod, CfnApi } from 'aws-cdk-lib/aws-apigatewayv2';
348
398
  import { HttpIamAuthorizer } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
349
399
  import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
@@ -392,7 +442,7 @@ export class TestApi<
392
442
  operations: OPERATION_DETAILS,
393
443
  defaultIntegrationOptions: {
394
444
  runtime: Runtime.PYTHON_3_12,
395
- handler: 'proj_test_api.main.handler',
445
+ handler: 'run.sh',
396
446
  code: Code.fromAsset(
397
447
  url.fileURLToPath(
398
448
  new URL(
@@ -403,17 +453,29 @@ export class TestApi<
403
453
  ),
404
454
  timeout: Duration.seconds(30),
405
455
  tracing: Tracing.ACTIVE,
456
+ snapStart: SnapStartConf.ON_PUBLISHED_VERSIONS,
406
457
  environment: {
407
458
  AWS_CONNECTION_REUSE_ENABLED: '1',
459
+ PORT: '8000',
460
+ AWS_LWA_INVOKE_MODE: 'buffered',
461
+ AWS_LAMBDA_EXEC_WRAPPER: '/opt/bootstrap',
408
462
  },
409
463
  } satisfies FunctionProps,
410
464
  buildDefaultIntegration: (op, props: FunctionProps) => {
411
465
  const handler = new Function(scope, \`TestApi\${op}Handler\`, props);
466
+ const stack = Stack.of(scope);
467
+ handler.addLayers(
468
+ LayerVersion.fromLayerVersionArn(
469
+ scope,
470
+ \`TestApi\${op}LWALayer\`,
471
+ \`arn:aws:lambda:\${stack.region}:753240598075:layer:LambdaAdapterLayerX86:24\`,
472
+ ),
473
+ );
412
474
  return {
413
475
  handler,
414
476
  integration: new HttpLambdaIntegration(
415
477
  \`TestApi\${op}Integration\`,
416
- handler,
478
+ handler.currentVersion,
417
479
  ),
418
480
  };
419
481
  },
@@ -875,13 +937,16 @@ import {
875
937
  Function,
876
938
  FunctionProps,
877
939
  Tracing,
940
+ LayerVersion,
941
+ SnapStartConf,
878
942
  } from 'aws-cdk-lib/aws-lambda';
879
943
  import {
880
944
  AuthorizationType,
881
945
  Cors,
882
946
  LambdaIntegration,
947
+ ResponseTransferMode,
883
948
  } from 'aws-cdk-lib/aws-apigateway';
884
- import { Duration } from 'aws-cdk-lib';
949
+ import { Duration, Stack } from 'aws-cdk-lib';
885
950
  import {
886
951
  PolicyDocument,
887
952
  PolicyStatement,
@@ -934,7 +999,7 @@ export class TestApi<
934
999
  operations: OPERATION_DETAILS,
935
1000
  defaultIntegrationOptions: {
936
1001
  runtime: Runtime.PYTHON_3_12,
937
- handler: 'proj_test_api.main.handler',
1002
+ handler: 'run.sh',
938
1003
  code: Code.fromAsset(
939
1004
  url.fileURLToPath(
940
1005
  new URL(
@@ -945,15 +1010,29 @@ export class TestApi<
945
1010
  ),
946
1011
  timeout: Duration.seconds(30),
947
1012
  tracing: Tracing.ACTIVE,
1013
+ snapStart: SnapStartConf.ON_PUBLISHED_VERSIONS,
948
1014
  environment: {
949
1015
  AWS_CONNECTION_REUSE_ENABLED: '1',
1016
+ PORT: '8000',
1017
+ AWS_LWA_INVOKE_MODE: 'response_stream',
1018
+ AWS_LAMBDA_EXEC_WRAPPER: '/opt/bootstrap',
950
1019
  },
951
1020
  } satisfies FunctionProps,
952
1021
  buildDefaultIntegration: (op, props: FunctionProps) => {
953
1022
  const handler = new Function(scope, \`TestApi\${op}Handler\`, props);
1023
+ const stack = Stack.of(scope);
1024
+ handler.addLayers(
1025
+ LayerVersion.fromLayerVersionArn(
1026
+ scope,
1027
+ \`TestApi\${op}LWALayer\`,
1028
+ \`arn:aws:lambda:\${stack.region}:753240598075:layer:LambdaAdapterLayerX86:24\`,
1029
+ ),
1030
+ );
954
1031
  return {
955
1032
  handler,
956
- integration: new LambdaIntegration(handler),
1033
+ integration: new LambdaIntegration(handler.currentVersion, {
1034
+ responseTransferMode: ResponseTransferMode.STREAM,
1035
+ }),
957
1036
  };
958
1037
  },
959
1038
  });
@@ -1658,10 +1737,12 @@ resource "aws_lambda_function" "api_lambda" {
1658
1737
  filename = data.archive_file.lambda_zip.output_path
1659
1738
  function_name = "TestApiHandler"
1660
1739
  role = aws_iam_role.lambda_execution_role.arn
1661
- handler = "proj_test_api.main.handler"
1740
+ handler = "run.sh"
1662
1741
  runtime = "python3.12"
1742
+ layers = ["arn:aws:lambda:\${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:24"]
1663
1743
  timeout = 30
1664
1744
  memory_size = 128
1745
+ publish = true
1665
1746
 
1666
1747
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
1667
1748
 
@@ -1670,9 +1751,17 @@ resource "aws_lambda_function" "api_lambda" {
1670
1751
  mode = "Active"
1671
1752
  }
1672
1753
 
1754
+ # Enable SnapStart for faster cold starts
1755
+ snap_start {
1756
+ apply_on = "PublishedVersions"
1757
+ }
1758
+
1673
1759
  environment {
1674
1760
  variables = merge({
1675
1761
  AWS_CONNECTION_REUSE_ENABLED = "1"
1762
+ PORT = "8000"
1763
+ AWS_LWA_INVOKE_MODE = "buffered"
1764
+ AWS_LAMBDA_EXEC_WRAPPER = "/opt/bootstrap"
1676
1765
  }, var.env)
1677
1766
  }
1678
1767
 
@@ -1732,6 +1821,15 @@ resource "aws_cloudwatch_log_group" "lambda_logs" {
1732
1821
  tags = var.tags
1733
1822
  }
1734
1823
 
1824
+ # Lambda alias pointing to the latest published version for SnapStart
1825
+ resource "aws_lambda_alias" "live" {
1826
+ name = "live"
1827
+ function_name = aws_lambda_function.api_lambda.function_name
1828
+ function_version = aws_lambda_function.api_lambda.version
1829
+
1830
+ depends_on = [aws_lambda_function.api_lambda]
1831
+ }
1832
+
1735
1833
  # Cognito User Pool Authorizer
1736
1834
  resource "aws_apigatewayv2_authorizer" "cognito_authorizer" {
1737
1835
  api_id = module.http_api.api_id
@@ -1749,12 +1847,12 @@ resource "aws_apigatewayv2_authorizer" "cognito_authorizer" {
1749
1847
  resource "aws_apigatewayv2_integration" "lambda_integration" {
1750
1848
  api_id = module.http_api.api_id
1751
1849
  integration_type = "AWS_PROXY"
1752
- integration_uri = aws_lambda_function.api_lambda.invoke_arn
1850
+ integration_uri = aws_lambda_alias.live.invoke_arn
1753
1851
 
1754
1852
  payload_format_version = "2.0"
1755
1853
  timeout_milliseconds = 30000
1756
1854
 
1757
- depends_on = [aws_lambda_function.api_lambda]
1855
+ depends_on = [aws_lambda_alias.live]
1758
1856
  }
1759
1857
 
1760
1858
  # Route for proxy integration (catches all requests)
@@ -1783,15 +1881,16 @@ module "add_url_to_runtime_config" {
1783
1881
  depends_on = [module.http_api]
1784
1882
  }
1785
1883
 
1786
- # Lambda permission for API Gateway to invoke the function
1884
+ # Lambda permission for API Gateway to invoke the function via alias
1787
1885
  resource "aws_lambda_permission" "api_gateway_invoke" {
1788
1886
  statement_id = "AllowExecutionFromAPIGateway"
1789
1887
  action = "lambda:InvokeFunction"
1790
1888
  function_name = aws_lambda_function.api_lambda.function_name
1889
+ qualifier = aws_lambda_alias.live.name
1791
1890
  principal = "apigateway.amazonaws.com"
1792
1891
  source_arn = "\${module.http_api.api_execution_arn}/*/*"
1793
1892
 
1794
- depends_on = [module.http_api, aws_lambda_function.api_lambda]
1893
+ depends_on = [module.http_api, aws_lambda_alias.live]
1795
1894
  }
1796
1895
 
1797
1896
  # Outputs
@@ -2278,10 +2377,12 @@ resource "aws_lambda_function" "api_lambda" {
2278
2377
  filename = data.archive_file.lambda_zip.output_path
2279
2378
  function_name = "TestApiHandler"
2280
2379
  role = aws_iam_role.lambda_execution_role.arn
2281
- handler = "proj_test_api.main.handler"
2380
+ handler = "run.sh"
2282
2381
  runtime = "python3.12"
2382
+ layers = ["arn:aws:lambda:\${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:24"]
2283
2383
  timeout = 30
2284
2384
  memory_size = 128
2385
+ publish = true
2285
2386
 
2286
2387
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
2287
2388
 
@@ -2290,9 +2391,17 @@ resource "aws_lambda_function" "api_lambda" {
2290
2391
  mode = "Active"
2291
2392
  }
2292
2393
 
2394
+ # Enable SnapStart for faster cold starts
2395
+ snap_start {
2396
+ apply_on = "PublishedVersions"
2397
+ }
2398
+
2293
2399
  environment {
2294
2400
  variables = merge({
2295
2401
  AWS_CONNECTION_REUSE_ENABLED = "1"
2402
+ PORT = "8000"
2403
+ AWS_LWA_INVOKE_MODE = "buffered"
2404
+ AWS_LAMBDA_EXEC_WRAPPER = "/opt/bootstrap"
2296
2405
  }, var.env)
2297
2406
  }
2298
2407
 
@@ -2352,17 +2461,26 @@ resource "aws_cloudwatch_log_group" "lambda_logs" {
2352
2461
  tags = var.tags
2353
2462
  }
2354
2463
 
2464
+ # Lambda alias pointing to the latest published version for SnapStart
2465
+ resource "aws_lambda_alias" "live" {
2466
+ name = "live"
2467
+ function_name = aws_lambda_function.api_lambda.function_name
2468
+ function_version = aws_lambda_function.api_lambda.version
2469
+
2470
+ depends_on = [aws_lambda_function.api_lambda]
2471
+ }
2472
+
2355
2473
 
2356
2474
  # Lambda integration for HTTP API
2357
2475
  resource "aws_apigatewayv2_integration" "lambda_integration" {
2358
2476
  api_id = module.http_api.api_id
2359
2477
  integration_type = "AWS_PROXY"
2360
- integration_uri = aws_lambda_function.api_lambda.invoke_arn
2478
+ integration_uri = aws_lambda_alias.live.invoke_arn
2361
2479
 
2362
2480
  payload_format_version = "2.0"
2363
2481
  timeout_milliseconds = 30000
2364
2482
 
2365
- depends_on = [aws_lambda_function.api_lambda]
2483
+ depends_on = [aws_lambda_alias.live]
2366
2484
  }
2367
2485
 
2368
2486
  # Route for proxy integration (catches all requests)
@@ -2390,15 +2508,16 @@ module "add_url_to_runtime_config" {
2390
2508
  depends_on = [module.http_api]
2391
2509
  }
2392
2510
 
2393
- # Lambda permission for API Gateway to invoke the function
2511
+ # Lambda permission for API Gateway to invoke the function via alias
2394
2512
  resource "aws_lambda_permission" "api_gateway_invoke" {
2395
2513
  statement_id = "AllowExecutionFromAPIGateway"
2396
2514
  action = "lambda:InvokeFunction"
2397
2515
  function_name = aws_lambda_function.api_lambda.function_name
2516
+ qualifier = aws_lambda_alias.live.name
2398
2517
  principal = "apigateway.amazonaws.com"
2399
2518
  source_arn = "\${module.http_api.api_execution_arn}/*/*"
2400
2519
 
2401
- depends_on = [module.http_api, aws_lambda_function.api_lambda]
2520
+ depends_on = [module.http_api, aws_lambda_alias.live]
2402
2521
  }
2403
2522
 
2404
2523
  # Outputs
@@ -2885,10 +3004,12 @@ resource "aws_lambda_function" "api_lambda" {
2885
3004
  filename = data.archive_file.lambda_zip.output_path
2886
3005
  function_name = "TestApiHandler"
2887
3006
  role = aws_iam_role.lambda_execution_role.arn
2888
- handler = "proj_test_api.main.handler"
3007
+ handler = "run.sh"
2889
3008
  runtime = "python3.12"
3009
+ layers = ["arn:aws:lambda:\${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:24"]
2890
3010
  timeout = 30
2891
3011
  memory_size = 128
3012
+ publish = true
2892
3013
 
2893
3014
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
2894
3015
 
@@ -2897,9 +3018,17 @@ resource "aws_lambda_function" "api_lambda" {
2897
3018
  mode = "Active"
2898
3019
  }
2899
3020
 
3021
+ # Enable SnapStart for faster cold starts
3022
+ snap_start {
3023
+ apply_on = "PublishedVersions"
3024
+ }
3025
+
2900
3026
  environment {
2901
3027
  variables = merge({
2902
3028
  AWS_CONNECTION_REUSE_ENABLED = "1"
3029
+ PORT = "8000"
3030
+ AWS_LWA_INVOKE_MODE = "buffered"
3031
+ AWS_LAMBDA_EXEC_WRAPPER = "/opt/bootstrap"
2903
3032
  }, var.env)
2904
3033
  }
2905
3034
 
@@ -2959,17 +3088,26 @@ resource "aws_cloudwatch_log_group" "lambda_logs" {
2959
3088
  tags = var.tags
2960
3089
  }
2961
3090
 
3091
+ # Lambda alias pointing to the latest published version for SnapStart
3092
+ resource "aws_lambda_alias" "live" {
3093
+ name = "live"
3094
+ function_name = aws_lambda_function.api_lambda.function_name
3095
+ function_version = aws_lambda_function.api_lambda.version
3096
+
3097
+ depends_on = [aws_lambda_function.api_lambda]
3098
+ }
3099
+
2962
3100
 
2963
3101
  # Lambda integration for HTTP API
2964
3102
  resource "aws_apigatewayv2_integration" "lambda_integration" {
2965
3103
  api_id = module.http_api.api_id
2966
3104
  integration_type = "AWS_PROXY"
2967
- integration_uri = aws_lambda_function.api_lambda.invoke_arn
3105
+ integration_uri = aws_lambda_alias.live.invoke_arn
2968
3106
 
2969
3107
  payload_format_version = "2.0"
2970
3108
  timeout_milliseconds = 30000
2971
3109
 
2972
- depends_on = [aws_lambda_function.api_lambda]
3110
+ depends_on = [aws_lambda_alias.live]
2973
3111
  }
2974
3112
 
2975
3113
  # Route for proxy integration (catches all requests)
@@ -2999,15 +3137,16 @@ module "add_url_to_runtime_config" {
2999
3137
  depends_on = [module.http_api]
3000
3138
  }
3001
3139
 
3002
- # Lambda permission for API Gateway to invoke the function
3140
+ # Lambda permission for API Gateway to invoke the function via alias
3003
3141
  resource "aws_lambda_permission" "api_gateway_invoke" {
3004
3142
  statement_id = "AllowExecutionFromAPIGateway"
3005
3143
  action = "lambda:InvokeFunction"
3006
3144
  function_name = aws_lambda_function.api_lambda.function_name
3145
+ qualifier = aws_lambda_alias.live.name
3007
3146
  principal = "apigateway.amazonaws.com"
3008
3147
  source_arn = "\${module.http_api.api_execution_arn}/*/*"
3009
3148
 
3010
- depends_on = [module.http_api, aws_lambda_function.api_lambda]
3149
+ depends_on = [module.http_api, aws_lambda_alias.live]
3011
3150
  }
3012
3151
 
3013
3152
  # Outputs
@@ -3382,10 +3521,12 @@ resource "aws_lambda_function" "api_lambda" {
3382
3521
  filename = data.archive_file.lambda_zip.output_path
3383
3522
  function_name = "TestApiHandler"
3384
3523
  role = aws_iam_role.lambda_execution_role.arn
3385
- handler = "proj_test_api.main.handler"
3524
+ handler = "run.sh"
3386
3525
  runtime = "python3.12"
3526
+ layers = ["arn:aws:lambda:\${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:24"]
3387
3527
  timeout = 30
3388
3528
  memory_size = 128
3529
+ publish = true
3389
3530
 
3390
3531
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
3391
3532
 
@@ -3394,9 +3535,17 @@ resource "aws_lambda_function" "api_lambda" {
3394
3535
  mode = "Active"
3395
3536
  }
3396
3537
 
3538
+ # Enable SnapStart for faster cold starts
3539
+ snap_start {
3540
+ apply_on = "PublishedVersions"
3541
+ }
3542
+
3397
3543
  environment {
3398
3544
  variables = merge({
3399
3545
  AWS_CONNECTION_REUSE_ENABLED = "1"
3546
+ PORT = "8000"
3547
+ AWS_LWA_INVOKE_MODE = "response_stream"
3548
+ AWS_LAMBDA_EXEC_WRAPPER = "/opt/bootstrap"
3400
3549
  }, var.env)
3401
3550
  }
3402
3551
 
@@ -3456,6 +3605,15 @@ resource "aws_cloudwatch_log_group" "lambda_logs" {
3456
3605
  tags = var.tags
3457
3606
  }
3458
3607
 
3608
+ # Lambda alias pointing to the latest published version for SnapStart
3609
+ resource "aws_lambda_alias" "live" {
3610
+ name = "live"
3611
+ function_name = aws_lambda_function.api_lambda.function_name
3612
+ function_version = aws_lambda_function.api_lambda.version
3613
+
3614
+ depends_on = [aws_lambda_function.api_lambda]
3615
+ }
3616
+
3459
3617
  # Cognito User Pool Authorizer
3460
3618
  resource "aws_api_gateway_authorizer" "cognito_authorizer" {
3461
3619
  name = "TestApiAuthorizer"
@@ -3480,9 +3638,11 @@ resource "aws_api_gateway_integration" "lambda_integration" {
3480
3638
 
3481
3639
  integration_http_method = "POST"
3482
3640
  type = "AWS_PROXY"
3483
- uri = aws_lambda_function.api_lambda.invoke_arn
3641
+ # Use the response streaming invocation path with the alias ARN for SnapStart
3642
+ uri = "arn:aws:apigateway:\${data.aws_region.current.name}:lambda:path/2021-11-15/functions/\${aws_lambda_alias.live.arn}/response-streaming-invocations"
3643
+ response_transfer_mode = "STREAM"
3484
3644
 
3485
- depends_on = [aws_lambda_function.api_lambda]
3645
+ depends_on = [aws_lambda_alias.live]
3486
3646
  }
3487
3647
 
3488
3648
  # Method for proxy integration
@@ -3614,15 +3774,28 @@ resource "aws_api_gateway_rest_api_policy" "api_policy" {
3614
3774
  })
3615
3775
  }
3616
3776
 
3617
- # Lambda permission for API Gateway to invoke the function
3777
+ # Lambda permission for API Gateway to invoke the function via alias
3618
3778
  resource "aws_lambda_permission" "api_gateway_invoke" {
3619
3779
  statement_id = "AllowExecutionFromAPIGateway"
3620
3780
  action = "lambda:InvokeFunction"
3621
3781
  function_name = aws_lambda_function.api_lambda.function_name
3782
+ qualifier = aws_lambda_alias.live.name
3622
3783
  principal = "apigateway.amazonaws.com"
3623
3784
  source_arn = "\${module.rest_api.api_execution_arn}/*/*"
3624
3785
 
3625
- depends_on = [module.rest_api, aws_lambda_function.api_lambda]
3786
+ depends_on = [module.rest_api, aws_lambda_alias.live]
3787
+ }
3788
+
3789
+ # Lambda permission for API Gateway to invoke with response streaming via alias
3790
+ resource "aws_lambda_permission" "api_gateway_invoke_streaming" {
3791
+ statement_id = "AllowStreamingFromAPIGateway"
3792
+ action = "lambda:InvokeFunctionWithResponseStream"
3793
+ function_name = aws_lambda_function.api_lambda.function_name
3794
+ qualifier = aws_lambda_alias.live.name
3795
+ principal = "apigateway.amazonaws.com"
3796
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
3797
+
3798
+ depends_on = [module.rest_api, aws_lambda_alias.live]
3626
3799
  }
3627
3800
 
3628
3801
  # Add API url to runtime config
@@ -4008,10 +4181,12 @@ resource "aws_lambda_function" "api_lambda" {
4008
4181
  filename = data.archive_file.lambda_zip.output_path
4009
4182
  function_name = "TestApiHandler"
4010
4183
  role = aws_iam_role.lambda_execution_role.arn
4011
- handler = "proj_test_api.main.handler"
4184
+ handler = "run.sh"
4012
4185
  runtime = "python3.12"
4186
+ layers = ["arn:aws:lambda:\${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:24"]
4013
4187
  timeout = 30
4014
4188
  memory_size = 128
4189
+ publish = true
4015
4190
 
4016
4191
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
4017
4192
 
@@ -4020,9 +4195,17 @@ resource "aws_lambda_function" "api_lambda" {
4020
4195
  mode = "Active"
4021
4196
  }
4022
4197
 
4198
+ # Enable SnapStart for faster cold starts
4199
+ snap_start {
4200
+ apply_on = "PublishedVersions"
4201
+ }
4202
+
4023
4203
  environment {
4024
4204
  variables = merge({
4025
4205
  AWS_CONNECTION_REUSE_ENABLED = "1"
4206
+ PORT = "8000"
4207
+ AWS_LWA_INVOKE_MODE = "response_stream"
4208
+ AWS_LAMBDA_EXEC_WRAPPER = "/opt/bootstrap"
4026
4209
  }, var.env)
4027
4210
  }
4028
4211
 
@@ -4082,6 +4265,15 @@ resource "aws_cloudwatch_log_group" "lambda_logs" {
4082
4265
  tags = var.tags
4083
4266
  }
4084
4267
 
4268
+ # Lambda alias pointing to the latest published version for SnapStart
4269
+ resource "aws_lambda_alias" "live" {
4270
+ name = "live"
4271
+ function_name = aws_lambda_function.api_lambda.function_name
4272
+ function_version = aws_lambda_function.api_lambda.version
4273
+
4274
+ depends_on = [aws_lambda_function.api_lambda]
4275
+ }
4276
+
4085
4277
 
4086
4278
  # Create proxy resource (captures all paths)
4087
4279
  resource "aws_api_gateway_resource" "proxy_resource" {
@@ -4098,9 +4290,11 @@ resource "aws_api_gateway_integration" "lambda_integration" {
4098
4290
 
4099
4291
  integration_http_method = "POST"
4100
4292
  type = "AWS_PROXY"
4101
- uri = aws_lambda_function.api_lambda.invoke_arn
4293
+ # Use the response streaming invocation path with the alias ARN for SnapStart
4294
+ uri = "arn:aws:apigateway:\${data.aws_region.current.name}:lambda:path/2021-11-15/functions/\${aws_lambda_alias.live.arn}/response-streaming-invocations"
4295
+ response_transfer_mode = "STREAM"
4102
4296
 
4103
- depends_on = [aws_lambda_function.api_lambda]
4297
+ depends_on = [aws_lambda_alias.live]
4104
4298
  }
4105
4299
 
4106
4300
  # Method for proxy integration
@@ -4242,15 +4436,28 @@ resource "aws_api_gateway_rest_api_policy" "api_policy" {
4242
4436
  })
4243
4437
  }
4244
4438
 
4245
- # Lambda permission for API Gateway to invoke the function
4439
+ # Lambda permission for API Gateway to invoke the function via alias
4246
4440
  resource "aws_lambda_permission" "api_gateway_invoke" {
4247
4441
  statement_id = "AllowExecutionFromAPIGateway"
4248
4442
  action = "lambda:InvokeFunction"
4249
4443
  function_name = aws_lambda_function.api_lambda.function_name
4444
+ qualifier = aws_lambda_alias.live.name
4250
4445
  principal = "apigateway.amazonaws.com"
4251
4446
  source_arn = "\${module.rest_api.api_execution_arn}/*/*"
4252
4447
 
4253
- depends_on = [module.rest_api, aws_lambda_function.api_lambda]
4448
+ depends_on = [module.rest_api, aws_lambda_alias.live]
4449
+ }
4450
+
4451
+ # Lambda permission for API Gateway to invoke with response streaming via alias
4452
+ resource "aws_lambda_permission" "api_gateway_invoke_streaming" {
4453
+ statement_id = "AllowStreamingFromAPIGateway"
4454
+ action = "lambda:InvokeFunctionWithResponseStream"
4455
+ function_name = aws_lambda_function.api_lambda.function_name
4456
+ qualifier = aws_lambda_alias.live.name
4457
+ principal = "apigateway.amazonaws.com"
4458
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
4459
+
4460
+ depends_on = [module.rest_api, aws_lambda_alias.live]
4254
4461
  }
4255
4462
 
4256
4463
  # Add API url to runtime config
@@ -4636,10 +4843,12 @@ resource "aws_lambda_function" "api_lambda" {
4636
4843
  filename = data.archive_file.lambda_zip.output_path
4637
4844
  function_name = "TestApiHandler"
4638
4845
  role = aws_iam_role.lambda_execution_role.arn
4639
- handler = "proj_test_api.main.handler"
4846
+ handler = "run.sh"
4640
4847
  runtime = "python3.12"
4848
+ layers = ["arn:aws:lambda:\${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:24"]
4641
4849
  timeout = 30
4642
4850
  memory_size = 128
4851
+ publish = true
4643
4852
 
4644
4853
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
4645
4854
 
@@ -4648,9 +4857,17 @@ resource "aws_lambda_function" "api_lambda" {
4648
4857
  mode = "Active"
4649
4858
  }
4650
4859
 
4860
+ # Enable SnapStart for faster cold starts
4861
+ snap_start {
4862
+ apply_on = "PublishedVersions"
4863
+ }
4864
+
4651
4865
  environment {
4652
4866
  variables = merge({
4653
4867
  AWS_CONNECTION_REUSE_ENABLED = "1"
4868
+ PORT = "8000"
4869
+ AWS_LWA_INVOKE_MODE = "response_stream"
4870
+ AWS_LAMBDA_EXEC_WRAPPER = "/opt/bootstrap"
4654
4871
  }, var.env)
4655
4872
  }
4656
4873
 
@@ -4710,6 +4927,15 @@ resource "aws_cloudwatch_log_group" "lambda_logs" {
4710
4927
  tags = var.tags
4711
4928
  }
4712
4929
 
4930
+ # Lambda alias pointing to the latest published version for SnapStart
4931
+ resource "aws_lambda_alias" "live" {
4932
+ name = "live"
4933
+ function_name = aws_lambda_function.api_lambda.function_name
4934
+ function_version = aws_lambda_function.api_lambda.version
4935
+
4936
+ depends_on = [aws_lambda_function.api_lambda]
4937
+ }
4938
+
4713
4939
 
4714
4940
  # Create proxy resource (captures all paths)
4715
4941
  resource "aws_api_gateway_resource" "proxy_resource" {
@@ -4726,9 +4952,11 @@ resource "aws_api_gateway_integration" "lambda_integration" {
4726
4952
 
4727
4953
  integration_http_method = "POST"
4728
4954
  type = "AWS_PROXY"
4729
- uri = aws_lambda_function.api_lambda.invoke_arn
4955
+ # Use the response streaming invocation path with the alias ARN for SnapStart
4956
+ uri = "arn:aws:apigateway:\${data.aws_region.current.name}:lambda:path/2021-11-15/functions/\${aws_lambda_alias.live.arn}/response-streaming-invocations"
4957
+ response_transfer_mode = "STREAM"
4730
4958
 
4731
- depends_on = [aws_lambda_function.api_lambda]
4959
+ depends_on = [aws_lambda_alias.live]
4732
4960
  }
4733
4961
 
4734
4962
  # Method for proxy integration
@@ -4861,15 +5089,28 @@ resource "aws_api_gateway_rest_api_policy" "api_policy" {
4861
5089
  })
4862
5090
  }
4863
5091
 
4864
- # Lambda permission for API Gateway to invoke the function
5092
+ # Lambda permission for API Gateway to invoke the function via alias
4865
5093
  resource "aws_lambda_permission" "api_gateway_invoke" {
4866
5094
  statement_id = "AllowExecutionFromAPIGateway"
4867
5095
  action = "lambda:InvokeFunction"
4868
5096
  function_name = aws_lambda_function.api_lambda.function_name
5097
+ qualifier = aws_lambda_alias.live.name
5098
+ principal = "apigateway.amazonaws.com"
5099
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
5100
+
5101
+ depends_on = [module.rest_api, aws_lambda_alias.live]
5102
+ }
5103
+
5104
+ # Lambda permission for API Gateway to invoke with response streaming via alias
5105
+ resource "aws_lambda_permission" "api_gateway_invoke_streaming" {
5106
+ statement_id = "AllowStreamingFromAPIGateway"
5107
+ action = "lambda:InvokeFunctionWithResponseStream"
5108
+ function_name = aws_lambda_function.api_lambda.function_name
5109
+ qualifier = aws_lambda_alias.live.name
4869
5110
  principal = "apigateway.amazonaws.com"
4870
5111
  source_arn = "\${module.rest_api.api_execution_arn}/*/*"
4871
5112
 
4872
- depends_on = [module.rest_api, aws_lambda_function.api_lambda]
5113
+ depends_on = [module.rest_api, aws_lambda_alias.live]
4873
5114
  }
4874
5115
 
4875
5116
  # Add API url to runtime config