Skip to content

Commit ff507b1

Browse files
committed
docs: update template & functions
1 parent 6e5e6c9 commit ff507b1

File tree

4 files changed

+60
-27
lines changed

4 files changed

+60
-27
lines changed

examples/cdk/functions/commons/constants.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ import { getStringFromEnv } from '#helpers/utils';
22

33
// Get the DynamoDB table name from environment variables
44
const itemsTableName = getStringFromEnv('TABLE_NAME');
5-
const ssmParameterName = getStringFromEnv('SSM_PARAMETER_NAME');
65

7-
export { itemsTableName, ssmParameterName };
6+
export { itemsTableName };
Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import { assertIsError } from '#helpers/utils';
12
import { logger } from '#powertools/logger';
3+
import { tracer } from '#powertools/tracer';
24
import {
35
BatchProcessor,
46
EventType,
57
processPartialResponse,
68
} from '@aws-lambda-powertools/batch';
9+
import type { AttributeValue } from '@aws-sdk/client-dynamodb';
10+
import { unmarshall } from '@aws-sdk/util-dynamodb';
711
import type {
812
Context,
913
DynamoDBBatchResponse,
@@ -23,37 +27,46 @@ const processor = new BatchProcessor(EventType.DynamoDBStreams);
2327
* @param record The DynamoDB record to process
2428
*/
2529
const recordHandler = async (record: DynamoDBRecord): Promise<void> => {
30+
logger.debug('processing record', { record });
31+
const subsegment = tracer
32+
.getSegment()
33+
?.addNewSubsegment('#### recordHandler');
2634
try {
2735
if (record.dynamodb && record.dynamodb.NewImage) {
28-
const message = record.dynamodb.NewImage.Message?.S;
29-
if (message) {
30-
const payload = JSON.parse(message) as { id: string; name: string };
31-
// Add itemId to the logger so that it's included in every log message
32-
logger.appendKeys({ itemId: payload.id });
36+
const payload = unmarshall(
37+
record.dynamodb.NewImage as { [key: string]: AttributeValue }
38+
);
3339

34-
const query = new URLSearchParams();
35-
query.set('name', payload.name);
40+
// Add itemId to the logger so that it's included in every log message
41+
logger.appendKeys({ itemId: payload.id });
42+
// Also add it to the subsegment, so you can search for traces by itemId
43+
subsegment?.addAnnotation('itemId', payload.id);
3644

37-
const remoteUrl = `https://httpbin.org/anything?${query.toString()}`;
38-
logger.debug('sending request', { remoteUrl });
45+
const query = new URLSearchParams();
46+
query.set('name', payload.name);
3947

40-
// This request doesn't show up in the trace yet, see #1619 for updates
41-
const response = await fetch(remoteUrl);
42-
// If the request was successful, the response.ok property will be true
43-
equal(response.ok, true);
48+
const remoteUrl = `https://httpbin.org/anything?${query.toString()}`;
49+
logger.debug('sending request', { remoteUrl });
4450

45-
logger.debug('request completed', {
46-
response: await response.json(),
47-
status: response.status,
48-
});
49-
}
51+
// This request doesn't show up in the trace yet, see #1619 for updates
52+
const response = await fetch(remoteUrl);
53+
// If the request was successful, the response.ok property will be true
54+
equal(response.ok, true);
55+
56+
logger.debug('request completed', {
57+
response: await response.json(),
58+
status: response.status,
59+
});
5060
}
5161
} catch (error) {
52-
logger.error('error processing record', { error });
62+
assertIsError(error);
63+
logger.error('error processing record', error);
64+
subsegment?.addError(error, true);
5365

5466
throw error;
5567
} finally {
5668
logger.removeKeys(['itemId']);
69+
subsegment?.close();
5770
}
5871
};
5972

@@ -62,10 +75,24 @@ const recordHandler = async (record: DynamoDBRecord): Promise<void> => {
6275
*
6376
* The functions uses the `processPartialResponse` function from the `@aws-lambda-powertools/batch` package
6477
* to process the records in parallel using the `recordHandler` function.
78+
*
79+
* The `processPartialResponse` is wrapped in a `tracer.provider.captureAsyncFunc` to ensure that the whole
80+
* process is captured in a single trace.
6581
*/
6682
export const handler = async (
6783
event: DynamoDBStreamEvent,
6884
context: Context
6985
): Promise<DynamoDBBatchResponse> => {
70-
return processPartialResponse(event, recordHandler, processor, { context });
86+
return tracer.provider.captureAsyncFunc('### handler', async (segment) => {
87+
const result = await processPartialResponse(
88+
event,
89+
recordHandler,
90+
processor,
91+
{ context }
92+
);
93+
94+
segment?.close();
95+
96+
return result;
97+
}) as DynamoDBBatchResponse;
7198
};

examples/cdk/functions/put-item.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { ssmParameterName } from '#constants';
1+
import { ddbClient } from '#clients/dynamodb';
22
import { getSSMStringParameter } from '#helpers/get-string-param';
33
import { putItemInDynamoDB } from '#helpers/put-item';
4-
import { assertIsError } from '#helpers/utils';
4+
import { assertIsError, getStringFromEnv } from '#helpers/utils';
55
import { logger, metrics, tracer } from '#powertools';
66
import {
77
IdempotencyConfig,
@@ -17,12 +17,15 @@ import type {
1717
import type { Subsegment } from 'aws-xray-sdk-core';
1818

1919
// Initialize the persistence store for idempotency
20+
const ssmParameterName = getStringFromEnv('SSM_PARAMETER_NAME');
2021
const persistenceStore = new DynamoDBPersistenceLayer({
2122
tableName: await getSSMStringParameter(ssmParameterName),
23+
// Pass DynamoDB client, so we can trace the calls
24+
awsSdkV3Client: ddbClient,
2225
});
2326
// Define the idempotency configuration
2427
const idempotencyConfig = new IdempotencyConfig({
25-
useLocalCache: true,
28+
useLocalCache: false,
2629
maxLocalCacheSize: 500,
2730
expiresAfterSeconds: 60 * 60 * 24,
2831
});

examples/cdk/src/example-stack.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ export class CdkAppStack extends Stack {
3131
'powertools-layer',
3232
`arn:aws:lambda:${
3333
Stack.of(this).region
34-
//}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:2` // doesn't work with ESM see
35-
}:536254204126:layer:Layers-E2E-20-x86-1f6e3-layerStack:1`
34+
}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:3`
3635
);
3736

3837
// Items table
@@ -88,6 +87,7 @@ export class CdkAppStack extends Stack {
8887
keepNames: true,
8988
format: OutputFormat.ESM,
9089
sourcesContent: true,
90+
mainFields: ['module', 'main'],
9191
externalModules: [], // we bundle all the dependencies
9292
esbuildArgs: {
9393
'--tree-shaking': 'true',
@@ -131,6 +131,7 @@ export class CdkAppStack extends Stack {
131131
sourceMap: true,
132132
keepNames: true,
133133
format: OutputFormat.ESM,
134+
mainFields: ['module', 'main'],
134135
sourcesContent: true,
135136
externalModules: ['@aws-sdk/*', '@aws-lambda-powertools/*'], // the dependencies are included in the layer
136137
esbuildArgs: {
@@ -155,6 +156,7 @@ export class CdkAppStack extends Stack {
155156
sourceMap: true,
156157
keepNames: true,
157158
format: OutputFormat.CJS,
159+
mainFields: ['main'],
158160
sourcesContent: true,
159161
externalModules: [], // we bundle all the dependencies
160162
},
@@ -177,6 +179,7 @@ export class CdkAppStack extends Stack {
177179
sourceMap: true,
178180
keepNames: true,
179181
format: OutputFormat.CJS,
182+
mainFields: ['main'],
180183
sourcesContent: true,
181184
externalModules: ['@aws-sdk/*', '@aws-lambda-powertools/*'], // the dependencies are included in the layer
182185
},
@@ -196,6 +199,7 @@ export class CdkAppStack extends Stack {
196199
batchSize: 100,
197200
retryAttempts: 3,
198201
filters: [
202+
// Filter by the INSERT event type and the presence of the id and name attributes
199203
FilterCriteria.filter({
200204
eventName: FilterRule.isEqual('INSERT'),
201205
dynamodb: {

0 commit comments

Comments
 (0)