Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
- [Advanced Settings](#advanced-settings)
- [YAML Settings](#yaml-settings)
- [Advanced Usage](#advanced-usage)
- [Keeping The Server Warm](#keeping-the-server-warm)
- [Keeping The Server Warm (Deprecated)](#keeping-the-server-warm-deprecated)
- [Serving Static Files / Binary Uploads](#serving-static-files--binary-uploads)
- [Enabling CORS](#enabling-cors)
- [Large Projects](#large-projects)
Expand Down Expand Up @@ -1239,8 +1239,8 @@ to change Zappa's behavior. Use these at your own risk!
"token_header": "Authorization", // Optional. Default 'Authorization'. The name of a custom authorization header containing the token that clients submit as part of their requests.
"validation_expression": "^Bearer \\w+$", // Optional. A validation expression for the incoming token, specify a regular expression.
},
"keep_warm": true, // Create CloudWatch events to keep the server warm. Default true. To remove, set to false and then `unschedule`.
"keep_warm_expression": "rate(4 minutes)", // How often to execute the keep-warm, in cron and rate format. Default 4 minutes.
"keep_warm": false, // Deprecated. Create CloudWatch events to keep the server warm. Default false. Does not reduce cold start duration. Consider snap_start or provisioned_concurrency instead. See #1451.
"keep_warm_expression": "rate(4 minutes)", // How often to execute the keep-warm, in cron and rate format. Default 4 minutes. Only used when keep_warm is true.
"lambda_description": "Your Description", // However you want to describe your project for the AWS console. Default "Zappa Deployment".
"lambda_handler": "your_custom_handler", // The name of Lambda handler. Default: handler.lambda_handler
"layers": ["arn:aws:lambda:<region>:<account_id>:layer:<layer_name>:<layer_version>"], // optional lambda layers
Expand Down Expand Up @@ -1317,9 +1317,11 @@ Similarly, you can supply a `zappa_settings.toml` file:

## Advanced Usage

### Keeping The Server Warm
### Keeping The Server Warm (Deprecated)

Zappa will automatically set up a regularly occurring execution of your application in order to keep the Lambda function warm. This can be disabled via the `keep_warm` setting.
> **Deprecated**: `keep_warm` is disabled by default and will be removed in a future version. Investigation ([#1445](https://github.com/zappa/Zappa/issues/1445)) found that `keep_warm` does not reduce cold start duration — only frequency for a single execution environment. Use `snap_start` (45-72% faster cold starts, ~$1.95/mo) or `provisioned_concurrency` (eliminates cold starts entirely, ~$5.40/mo) instead. See [#1451](https://github.com/zappa/Zappa/issues/1451).

Zappa can set up a regularly occurring execution of your application in order to keep the Lambda function warm. This can be enabled via the `keep_warm` setting.

#### Serving Static Files / Binary Uploads

Expand Down
73 changes: 73 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4557,5 +4557,78 @@ def test_upload_to_s3_reraises_unexpected_errors(self):
z.s3_client.create_bucket.assert_not_called()


class TestKeepWarmDeprecation(unittest.TestCase):
def setUp(self):
self.users_current_region_name = os.environ.get("AWS_DEFAULT_REGION", None)
os.environ["AWS_DEFAULT_REGION"] = "us-east-1"

def tearDown(self):
del os.environ["AWS_DEFAULT_REGION"]
if self.users_current_region_name is not None:
os.environ["AWS_DEFAULT_REGION"] = self.users_current_region_name

def test_keep_warm_default_false(self):
"""keep_warm should default to false after deprecation."""
zappa_cli = ZappaCLI()
zappa_cli.api_stage = "ttt888"
zappa_cli.load_settings("test_settings.json")
# Default should be False when not explicitly set
self.assertFalse(zappa_cli.stage_config.get("keep_warm", False))

def test_keep_warm_deprecation_warning(self):
"""schedule() should emit a deprecation warning when keep_warm is enabled."""
zappa_cli = ZappaCLI()
zappa_cli.api_stage = "ttt888"
zappa_cli.load_settings("test_settings.json")
zappa_cli.override_stage_config_setting("keep_warm", True)
zappa_cli.override_stage_config_setting("events", [])
zappa_cli.lambda_name = "test-lambda"

zappa_cli.zappa = mock.MagicMock()
zappa_cli.zappa.lambda_client.get_function.return_value = {
"Configuration": {"FunctionArn": "arn:aws:lambda:us-east-1:123:function:test"}
}

with mock.patch("click.echo") as mock_echo:
zappa_cli.schedule()

echo_calls = " ".join(str(c) for c in mock_echo.call_args_list)
self.assertIn("deprecated", echo_calls)
self.assertIn("snap_start", echo_calls)
self.assertIn("provisioned_concurrency", echo_calls)

def test_keep_warm_no_warning_when_disabled(self):
"""schedule() should not emit a deprecation warning when keep_warm is false."""
zappa_cli = ZappaCLI()
zappa_cli.api_stage = "ttt888"
zappa_cli.load_settings("test_settings.json")
zappa_cli.override_stage_config_setting("keep_warm", False)
zappa_cli.override_stage_config_setting("events", [])
zappa_cli.lambda_name = "test-lambda"

with mock.patch("click.echo") as mock_echo:
zappa_cli.schedule()

echo_calls = " ".join(str(c) for c in mock_echo.call_args_list)
self.assertNotIn("deprecated", echo_calls)

def test_keep_warm_callback_deprecation_warning(self):
"""keep_warm_callback should emit a DeprecationWarning."""
import warnings

from zappa.handler import keep_warm_callback

mock_context = mock.MagicMock()

with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
with mock.patch("zappa.handler.lambda_handler"):
keep_warm_callback(event={}, context=mock_context)

self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, DeprecationWarning))
self.assertIn("deprecated", str(w[0].message))


if __name__ == "__main__":
unittest.main()
16 changes: 15 additions & 1 deletion zappa/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1452,7 +1452,21 @@ def schedule(self):
for event in events:
self.collision_warning(event.get("function"))

if self.stage_config.get("keep_warm", True):
keep_warm = self.stage_config.get("keep_warm", False)
if keep_warm:
click.echo(
click.style("Warning!", fg="yellow", bold=True)
+ " keep_warm is "
+ click.style("deprecated", bold=True)
+ " and disabled by default."
+ " It does not reduce cold start duration — only frequency for a single execution environment."
+ " Consider using "
+ click.style("snap_start", bold=True)
+ " or "
+ click.style("provisioned_concurrency", bold=True)
+ " instead."
+ " See https://github.com/zappa/Zappa/issues/1451"
)
if not events:
events = []

Expand Down
16 changes: 15 additions & 1 deletion zappa/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,21 @@ def lambda_handler(event, context): # pragma: no cover


def keep_warm_callback(event, context):
"""Method is triggered by the CloudWatch event scheduled when keep_warm setting is set to true."""
"""Deprecated: Method is triggered by the CloudWatch event scheduled when keep_warm setting is set to true.

keep_warm does not reduce cold start duration — only frequency for a single execution environment.
Consider using snap_start or provisioned_concurrency instead.
See https://github.com/zappa/Zappa/issues/1451
"""
import warnings

warnings.warn(
"keep_warm is deprecated and will be removed in a future version. "
"Use snap_start or provisioned_concurrency instead. "
"See https://github.com/zappa/Zappa/issues/1451",
DeprecationWarning,
stacklevel=1,
)
lambda_handler(event={}, context=context) # overriding event with an empty one so that web app initialization will
# be triggered.

Expand Down
Loading