@ashishpandeyone/cdk-lambda-web-function 0.1.2 → 0.1.4

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.
package/README.md CHANGED
@@ -156,6 +156,25 @@ const signed = await signer.sign(
156
156
  const response = await fetch(`https://${host}/`, { headers: signed.headers });
157
157
  ```
158
158
 
159
+ ### Functions defined elsewhere
160
+
161
+ Import a Web Function defined in another stack or app to grant access to it, read its metrics, or reference its revisions:
162
+
163
+ ```ts
164
+ const orders = WebFunction.fromWebFunctionArn(this, 'Orders', 'arn:aws:lambda:us-east-1:111122223333:web-function/orders');
165
+ orders.grantInvoke(consumerRole); // every endpoint of the function
166
+
167
+ const live = WebFunction.fromWebFunctionAttributes(this, 'Live', {
168
+ webFunctionName: 'orders', // in this stack's account and region
169
+ endpointName: 'live', // grantInvoke allows this endpoint only
170
+ });
171
+ live.metricConcurrentRequests().createAlarm(this, 'Busy', { threshold: 60, evaluationPeriods: 3 });
172
+ ```
173
+
174
+ An imported function's metrics default to its own region. Its endpoints, revisions and log groups stay with the stack that defines it.
175
+
176
+ `grantInvoke` adds to the caller's IAM policy, which is all a caller in the function's account needs. A caller in another account also needs the function's resource policy to allow it, which this library doesn't manage yet.
177
+
159
178
  ## Configuration
160
179
 
161
180
  ```ts
@@ -207,7 +226,9 @@ new NodejsWebFunction(this, 'Api', {
207
226
 
208
227
  `code` takes any `lambda.Code` that produces a zip in S3: `fromAsset`, `fromBucket`/`fromBucketV2`, `fromCustomCommand`, `fromDockerBuild`. Inline code and container images fail at synth time.
209
228
 
210
- Lambda Web Functions download code as the `lambda.amazonaws.com` service principal, from a **versioned** bucket, and the CDK bootstrap bucket allows neither. So each stack gets a small code bucket, and the code is copied into it on deploy.
229
+ Lambda Web Functions download code as the `lambda.amazonaws.com` service principal, from a **versioned** bucket, and the CDK bootstrap bucket allows neither. So each stack gets a small code bucket, and the code is copied into it on deploy. The bucket is emptied and deleted with the stack.
230
+
231
+ Code copies, log groups in other regions, revision cleanup and the bucket's emptying run in one custom resource Lambda per stack. Its logs go to a log group the stack owns, kept for a month and deleted with the stack.
211
232
 
212
233
  ## Revisions
213
234
 
@@ -250,18 +271,18 @@ fn.addEndpoint('Stable', { authType: WebFunctionAuthType.AWS_IAM, revision: prev
250
271
  By default an endpoint moves all its traffic to a new revision at once. With `deployment`, it moves in steps instead, watching CloudWatch alarms: if one goes into ALARM, the endpoint goes back to the revision it served before and the deployment fails, so CloudFormation rolls the stack back.
251
272
 
252
273
  ```ts
253
- // errorRate: a cloudwatch.IAlarm, for example on the share of 5xx responses
254
274
  const api = new WebFunction(this, 'Api', {
255
275
  runtime: lambda.Runtime.NODEJS_24_X,
256
276
  code: lambda.Code.fromAsset('dist'),
257
277
  authType: WebFunctionAuthType.AWS_IAM,
258
278
  endpoint: {
259
- // 10% of the traffic for 10 minutes, then all of it.
260
- deployment: WebFunctionDeployment.canary({ percent: 10, bake: Duration.minutes(10), alarms: [errorRate] }),
279
+ // 10% of the traffic for 10 minutes, then all of it; back if more than 2% of requests get a 5XX.
280
+ deployment: WebFunctionDeployment.canary({ percent: 10, bake: Duration.minutes(10), rollbackOn: { serverErrorRate: 2 } }),
261
281
  },
262
282
  });
263
283
 
264
- // 25% more every 5 minutes. Each endpoint has its own deployment.
284
+ // 25% more every 5 minutes, watching an alarm of your own. Each endpoint has its own deployment.
285
+ // errorRate: any cloudwatch.IAlarm, e.g. on a metric your application publishes.
265
286
  api.addEndpoint('Public', {
266
287
  authType: WebFunctionAuthType.NONE,
267
288
  deployment: WebFunctionDeployment.linear({ percent: 25, interval: Duration.minutes(5), alarms: [errorRate] }),
@@ -284,10 +305,52 @@ How it works:
284
305
  - A deployment can take up to an hour: CloudFormation waits for it before it updates the endpoint. Deployments of different endpoints run in parallel.
285
306
  - A canary or linear endpoint always moves to the current revision, so it can't also use `revision`, `additionalRevisions` or `routeTraffic()`. Use `allAtOnce()` to deploy a fix immediately, for example while an alarm is in ALARM.
286
307
 
287
- Lambda Web Function metrics have no revision dimension, so an alarm sees the whole endpoint: at 10%, a new revision's errors are a tenth of the endpoint's. Alarm on a rate, with a threshold low enough to notice that, or publish metrics from your application that carry its version. A bake should be longer than an alarm needs to fire (its period times its evaluation periods).
308
+ #### Rollback alarms
309
+
310
+ `rollbackOn` makes the endpoint create alarms on its own error rates, and the deployment watches them alongside any `alarms` you pass:
311
+
312
+ | `rollbackOn` | Default | |
313
+ |---|---|---|
314
+ | `serverErrorRate` | none | roll back when more than this % of requests get a 5XX |
315
+ | `clientErrorRate` | none | the same for 4XX (including 429s from `rateLimit` and `maxEnvironments`) |
316
+ | `minimumRequests` | 10 | periods with fewer requests don't count, so one failed request out of two doesn't roll back |
317
+ | `period`, `evaluationPeriods` | 1 minute, 2 | consecutive periods over the threshold before rolling back |
318
+
319
+ - **One alarm per threshold in every region the endpoint serves from.** Metrics are published in the region that served the request, and an alarm can only watch metrics in its own region. The home region's alarm is a normal CloudFormation alarm; the others are created and deleted with the endpoint by a custom resource, and named `LambdaWeb-<function>-<endpoint>-5xx-rate` (or `-4xx-rate`). `endpoint.rollbackAlarms` lists them all, e.g. to add notifications to the home region's.
320
+ - **The alarms see the whole endpoint.** Lambda Web Function metrics have no revision dimension, so at 10% a new revision's errors are about a tenth of the endpoint's: set the threshold low enough to notice that, or alarm on metrics your application publishes with its version.
321
+ - **5XX includes the platform's 503s** while the endpoint scales up for a sudden burst, not only your application's errors.
322
+ - **A step should outlast the alarm.** CloudWatch needs `period` × `evaluationPeriods`, plus a couple of minutes of delay, to fire; the construct warns when a canary's bake or a linear interval is shorter.
288
323
 
289
324
  The deployment runs in a few resources per stack, created on first use: two Lambda functions, a Step Functions state machine that calls them every 15 seconds, and a log group.
290
325
 
326
+ ## Metrics
327
+
328
+ Endpoints and functions have helpers for their CloudWatch metrics (namespace `AWS/Lambda/Web`), like `lambda.Function`'s:
329
+
330
+ ```ts
331
+ fn.endpoint.metricServerErrorRate().createAlarm(this, 'ErrorRate', { threshold: 1, evaluationPeriods: 3 });
332
+ fn.endpoint.metricRequestThrottles().createAlarm(this, 'Throttled', { threshold: 10, evaluationPeriods: 3 });
333
+ fn.metricConcurrentRequests().createAlarm(this, 'Saturated', { threshold: 60, evaluationPeriods: 3 });
334
+ ```
335
+
336
+ | Endpoint | Metric |
337
+ |---|---|
338
+ | `metricRequests()` | `ExecutedRequests` (there's no separate 2XX count) |
339
+ | `metricClientErrors()`, `metricServerErrors()` | `HTTPResponseStatusClass4XX`, `HTTPResponseStatusClass5XX` |
340
+ | `metricClientErrorRate()`, `metricServerErrorRate()` | 4XX or 5XX as a % of requests (math expression) |
341
+ | `metricActiveEnvironments()` | `EndpointActiveEnvironments`, to compare with `maxEnvironments` |
342
+ | `metricRequestThrottles()`, `metricEnvironmentThrottles()` | 429s from `rateLimit` and from `maxEnvironments` |
343
+
344
+ | Function | Metric |
345
+ |---|---|
346
+ | `metricConcurrentRequests()` | `EnvironmentConcurrentRequests` (maximum), to compare with `maxConcurrencyPerEnvironment` |
347
+ | `metricMaxMemoryUsage()` | `EnvironmentMaxMemoryUsage` (maximum) |
348
+ | `metricActiveTime()`, `metricCpuTime()`, `metricResponseBytes()` | `EnvironmentActiveTime`, `EnvironmentCPUTime`, `ResponseBytes` |
349
+
350
+ - **Metrics stay in the region that served the request**; unlike logs, they aren't copied to the home region. Every helper takes `region`. Dashboards can show any region, but an alarm can only use metrics from its own stack's region.
351
+ - 4XX, 5XX and the throttle metrics only exist once they're non-zero: alarm on them with `treatMissingData: NOT_BREACHING`. The rate helpers count missing errors as 0.
352
+ - There's no latency metric. Publish one from your application (e.g. with the CloudWatch embedded metric format).
353
+
291
354
  ## Logs in every region
292
355
 
293
356
  Web Functions log in two tiers:
@@ -322,10 +385,9 @@ new WebFunction(this, 'Api', {
322
385
 
323
386
  ## Limitations
324
387
 
325
- - Not yet supported: importing existing functions, VPC access (network connectors), resource-policy permissions, KMS encryption, metrics helpers, tracing, and a CloudFront origin.
388
+ - Not yet supported: VPC access (network connectors), resource-policy permissions, KMS encryption, tracing, and a CloudFront origin.
326
389
  - `cdk deploy --hotswap` and `cdk watch` don't support Web Functions.
327
390
  - Quotas: 10 endpoints and about 50 revisions per function (Lambda cleans up older revisions automatically), and 10,000 requests per second per endpoint. Per account and region: 100,000 requests per second and 2,000 Arm64 vCPUs (each execution environment uses 2). The account quotas are adjustable, and new accounts start lower. See [Lambda quotas](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html).
328
- - The stack's custom resource provider Lambda keeps its own log group after the stack is deleted, as with other CDK custom resources.
329
391
 
330
392
  ## Development
331
393