@mytechtoday/augment-extensions 1.2.2 → 1.3.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.
- package/LICENSE +22 -22
- package/augment-extensions/domain-rules/software-architecture/README.md +143 -143
- package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -961
- package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -990
- package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -882
- package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -703
- package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -957
- package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -747
- package/augment-extensions/domain-rules/software-architecture/module.json +119 -119
- package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -763
- package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -409
- package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -684
- package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -1381
- package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -616
- package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -306
- package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -554
- package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -776
- package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -503
- package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -1199
- package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -351
- package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -556
- package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -797
- package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -1345
- package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -1039
- package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -711
- package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -568
- package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -961
- package/augment-extensions/visual-design/CHANGELOG.md +132 -0
- package/augment-extensions/visual-design/README.md +255 -0
- package/augment-extensions/visual-design/__tests__/README.md +119 -0
- package/augment-extensions/visual-design/__tests__/style-selector.test.ts +172 -0
- package/augment-extensions/visual-design/__tests__/vendor-styles.test.ts +214 -0
- package/augment-extensions/visual-design/domains/other/ai-prompt-helper.ts +157 -0
- package/augment-extensions/visual-design/domains/other/dotnet-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/linux-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/other/mobile-application.ts +157 -0
- package/augment-extensions/visual-design/domains/other/motion-picture.ts +156 -0
- package/augment-extensions/visual-design/domains/other/os-application.ts +156 -0
- package/augment-extensions/visual-design/domains/other/print-campaigns.ts +158 -0
- package/augment-extensions/visual-design/domains/other/web-app.ts +157 -0
- package/augment-extensions/visual-design/domains/other/website.ts +161 -0
- package/augment-extensions/visual-design/domains/other/windows-platform.ts +156 -0
- package/augment-extensions/visual-design/domains/web-page-styles/amazon-cloudscape.ts +506 -0
- package/augment-extensions/visual-design/domains/web-page-styles/google-modern.ts +615 -0
- package/augment-extensions/visual-design/domains/web-page-styles/microsoft-fluent.ts +531 -0
- package/augment-extensions/visual-design/examples/README.md +97 -0
- package/augment-extensions/visual-design/examples/ai-prompt-generation.md +233 -0
- package/augment-extensions/visual-design/examples/basic-usage.md +216 -0
- package/augment-extensions/visual-design/examples/domain-workflows.md +257 -0
- package/augment-extensions/visual-design/examples/vendor-comparison.md +247 -0
- package/augment-extensions/visual-design/module.json +78 -0
- package/augment-extensions/visual-design/style-selector.ts +177 -0
- package/augment-extensions/visual-design/types.ts +302 -0
- package/augment-extensions/visual-design/visual-design-core.ts +469 -0
- package/augment-extensions/workflows/adr-support/README.md +227 -0
- package/augment-extensions/workflows/adr-support/__tests__/adr-validator.test.ts +203 -0
- package/augment-extensions/workflows/adr-support/adr-validator.ts +162 -0
- package/augment-extensions/workflows/adr-support/examples/complete-lifecycle-example.md +449 -0
- package/augment-extensions/workflows/adr-support/examples/integration-example.md +580 -0
- package/augment-extensions/workflows/adr-support/examples/superseding-example.md +436 -0
- package/augment-extensions/workflows/adr-support/module.json +112 -0
- package/augment-extensions/workflows/adr-support/rules/adr-creation.md +372 -0
- package/augment-extensions/workflows/adr-support/rules/beads-integration.md +443 -0
- package/augment-extensions/workflows/adr-support/rules/conflict-detection.md +486 -0
- package/augment-extensions/workflows/adr-support/rules/decision-detection.md +362 -0
- package/augment-extensions/workflows/adr-support/rules/lifecycle-management.md +427 -0
- package/augment-extensions/workflows/adr-support/rules/openspec-integration.md +465 -0
- package/augment-extensions/workflows/adr-support/rules/template-selection.md +405 -0
- package/augment-extensions/workflows/adr-support/rules/validation-rules.md +543 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-config.json +191 -0
- package/augment-extensions/workflows/adr-support/schemas/adr-metadata.json +172 -0
- package/augment-extensions/workflows/adr-support/templates/business-case.md +235 -0
- package/augment-extensions/workflows/adr-support/templates/madr-elaborate.md +197 -0
- package/augment-extensions/workflows/adr-support/templates/madr-simple.md +68 -0
- package/augment-extensions/workflows/adr-support/templates/nygard.md +84 -0
- package/augment-extensions/writing-standards/screenplay/rules/file-organization.md +213 -213
- package/augment-extensions/writing-standards/screenplay/utils/__tests__/file-organization.test.ts +169 -169
- package/augment-extensions/writing-standards/screenplay/utils/file-organization.ts +165 -165
- package/cli/dist/utils/auto-sync.js +19 -19
- package/package.json +5 -3
- package/augment-extensions/workflows/openspec/README.md +0 -96
- package/augment-extensions/workflows/openspec/examples/complete-change-example.md +0 -244
- package/augment-extensions/workflows/openspec/module.json +0 -54
- package/augment-extensions/workflows/openspec/rules/best-practices.md +0 -272
- package/augment-extensions/workflows/openspec/rules/manual-setup.md +0 -231
- package/augment-extensions/workflows/openspec/rules/spec-format.md +0 -236
- package/augment-extensions/workflows/openspec/rules/workflow.md +0 -214
package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md
CHANGED
|
@@ -1,711 +1,711 @@
|
|
|
1
|
-
# Serverless Architecture
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This document covers serverless architecture patterns, Function-as-a-Service (FaaS), stateless functions, and best practices for building event-driven, scalable applications without managing servers.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Knowledge
|
|
10
|
-
|
|
11
|
-
### What is Serverless Architecture?
|
|
12
|
-
|
|
13
|
-
**Definition**
|
|
14
|
-
- Cloud execution model where provider manages infrastructure
|
|
15
|
-
- Code runs in stateless compute containers
|
|
16
|
-
- Event-driven execution
|
|
17
|
-
- Automatic scaling
|
|
18
|
-
- Pay-per-execution pricing
|
|
19
|
-
|
|
20
|
-
**Core Principles**
|
|
21
|
-
- No server management
|
|
22
|
-
- Stateless functions
|
|
23
|
-
- Event-driven triggers
|
|
24
|
-
- Automatic scaling
|
|
25
|
-
- Built-in high availability
|
|
26
|
-
|
|
27
|
-
**Serverless Components**
|
|
28
|
-
|
|
29
|
-
**FaaS (Function-as-a-Service)**
|
|
30
|
-
- AWS Lambda, Azure Functions, Google Cloud Functions
|
|
31
|
-
- Execute code in response to events
|
|
32
|
-
- Millisecond billing
|
|
33
|
-
- Automatic scaling
|
|
34
|
-
|
|
35
|
-
**BaaS (Backend-as-a-Service)**
|
|
36
|
-
- Managed services: databases, authentication, storage
|
|
37
|
-
- Examples: AWS DynamoDB, Firebase, Auth0
|
|
38
|
-
- No infrastructure management
|
|
39
|
-
|
|
40
|
-
**Characteristics**
|
|
41
|
-
- Ephemeral execution (short-lived)
|
|
42
|
-
- Stateless (no persistent state in function)
|
|
43
|
-
- Cold start latency
|
|
44
|
-
- Execution time limits (e.g., 15 min for Lambda)
|
|
45
|
-
- Memory and CPU limits
|
|
46
|
-
|
|
47
|
-
### When to Use Serverless
|
|
48
|
-
|
|
49
|
-
**Good Fit**
|
|
50
|
-
- Event-driven workloads
|
|
51
|
-
- Unpredictable or variable traffic
|
|
52
|
-
- Microservices and APIs
|
|
53
|
-
- Data processing pipelines
|
|
54
|
-
- Scheduled tasks (cron jobs)
|
|
55
|
-
- Webhooks and integrations
|
|
56
|
-
- Prototypes and MVPs
|
|
57
|
-
|
|
58
|
-
**Poor Fit**
|
|
59
|
-
- Long-running processes (> 15 minutes)
|
|
60
|
-
- Stateful applications
|
|
61
|
-
- Predictable, constant high load
|
|
62
|
-
- Low-latency requirements (< 100ms)
|
|
63
|
-
- Complex orchestration
|
|
64
|
-
- Legacy applications
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Skills
|
|
69
|
-
|
|
70
|
-
### Function Design
|
|
71
|
-
|
|
72
|
-
**Stateless Functions**
|
|
73
|
-
```javascript
|
|
74
|
-
// Good: Stateless function
|
|
75
|
-
exports.handler = async (event) => {
|
|
76
|
-
const userId = event.pathParameters.userId;
|
|
77
|
-
|
|
78
|
-
// Get data from external source
|
|
79
|
-
const user = await dynamodb.get({
|
|
80
|
-
TableName: 'Users',
|
|
81
|
-
Key: { userId }
|
|
82
|
-
}).promise();
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
statusCode: 200,
|
|
86
|
-
body: JSON.stringify(user.Item)
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
// Bad: Stateful function (don't do this)
|
|
91
|
-
let requestCount = 0; // State persists across invocations!
|
|
92
|
-
|
|
93
|
-
exports.handler = async (event) => {
|
|
94
|
-
requestCount++; // Unreliable
|
|
95
|
-
// ...
|
|
96
|
-
};
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**Single Responsibility**
|
|
100
|
-
- One function, one purpose
|
|
101
|
-
- Small, focused functions
|
|
102
|
-
- Easy to test and maintain
|
|
103
|
-
- Independent deployment
|
|
104
|
-
|
|
105
|
-
**Function Size Guidelines**
|
|
106
|
-
- Keep functions small (< 500 lines)
|
|
107
|
-
- Minimize dependencies
|
|
108
|
-
- Fast cold start (< 3 seconds)
|
|
109
|
-
- Optimize package size
|
|
110
|
-
|
|
111
|
-
### Event Sources and Triggers
|
|
112
|
-
|
|
113
|
-
**HTTP Triggers**
|
|
114
|
-
- API Gateway → Lambda
|
|
115
|
-
- REST APIs
|
|
116
|
-
- Webhooks
|
|
117
|
-
- GraphQL endpoints
|
|
118
|
-
|
|
119
|
-
**Storage Triggers**
|
|
120
|
-
- S3 object created/deleted
|
|
121
|
-
- File processing
|
|
122
|
-
- Image resizing
|
|
123
|
-
- Data transformation
|
|
124
|
-
|
|
125
|
-
**Database Triggers**
|
|
126
|
-
- DynamoDB Streams
|
|
127
|
-
- Change data capture
|
|
128
|
-
- Audit logging
|
|
129
|
-
- Data replication
|
|
130
|
-
|
|
131
|
-
**Message Queue Triggers**
|
|
132
|
-
- SQS, SNS, EventBridge
|
|
133
|
-
- Asynchronous processing
|
|
134
|
-
- Event-driven workflows
|
|
135
|
-
- Decoupled systems
|
|
136
|
-
|
|
137
|
-
**Scheduled Triggers**
|
|
138
|
-
- CloudWatch Events (cron)
|
|
139
|
-
- Periodic tasks
|
|
140
|
-
- Batch processing
|
|
141
|
-
- Cleanup jobs
|
|
142
|
-
|
|
143
|
-
### Cold Start Optimization
|
|
144
|
-
|
|
145
|
-
**What is Cold Start?**
|
|
146
|
-
- First invocation after idle period
|
|
147
|
-
- Container initialization
|
|
148
|
-
- Code loading
|
|
149
|
-
- Dependency initialization
|
|
150
|
-
- Can add 1-5 seconds latency
|
|
151
|
-
|
|
152
|
-
**Optimization Techniques**
|
|
153
|
-
|
|
154
|
-
**Minimize Package Size**
|
|
155
|
-
```javascript
|
|
156
|
-
// Good: Import only what you need
|
|
157
|
-
const { DynamoDB } = require('aws-sdk');
|
|
158
|
-
|
|
159
|
-
// Bad: Import entire SDK
|
|
160
|
-
const AWS = require('aws-sdk');
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
**Lazy Loading**
|
|
164
|
-
```javascript
|
|
165
|
-
let dynamodb;
|
|
166
|
-
|
|
167
|
-
exports.handler = async (event) => {
|
|
168
|
-
// Initialize on first use
|
|
169
|
-
if (!dynamodb) {
|
|
170
|
-
const { DynamoDB } = require('aws-sdk');
|
|
171
|
-
dynamodb = new DynamoDB.DocumentClient();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Use dynamodb...
|
|
175
|
-
};
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
**Provisioned Concurrency**
|
|
179
|
-
- Keep functions warm
|
|
180
|
-
- Pre-initialized containers
|
|
181
|
-
- Eliminates cold starts
|
|
182
|
-
- Higher cost
|
|
183
|
-
|
|
184
|
-
**Connection Reuse**
|
|
185
|
-
```javascript
|
|
186
|
-
// Initialize outside handler (reused across invocations)
|
|
187
|
-
const { DynamoDB } = require('aws-sdk');
|
|
188
|
-
const dynamodb = new DynamoDB.DocumentClient();
|
|
189
|
-
|
|
190
|
-
exports.handler = async (event) => {
|
|
191
|
-
// Reuse connection
|
|
192
|
-
const result = await dynamodb.get({...}).promise();
|
|
193
|
-
return result;
|
|
194
|
-
};
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### State Management
|
|
198
|
-
|
|
199
|
-
**External State Storage**
|
|
200
|
-
- DynamoDB for NoSQL data
|
|
201
|
-
- RDS for relational data
|
|
202
|
-
- S3 for files and objects
|
|
203
|
-
- ElastiCache for caching
|
|
204
|
-
|
|
205
|
-
**Temporary State**
|
|
206
|
-
- /tmp directory (512 MB - 10 GB)
|
|
207
|
-
- Ephemeral (cleared between cold starts)
|
|
208
|
-
- Use for temporary files
|
|
209
|
-
|
|
210
|
-
**Distributed State**
|
|
211
|
-
- Step Functions for workflow state
|
|
212
|
-
- DynamoDB for shared state
|
|
213
|
-
- Parameter Store for configuration
|
|
214
|
-
- Secrets Manager for credentials
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## Examples
|
|
219
|
-
|
|
220
|
-
### REST API with Lambda and API Gateway
|
|
221
|
-
|
|
222
|
-
**Function: Get User**
|
|
223
|
-
```javascript
|
|
224
|
-
const { DynamoDB } = require('aws-sdk');
|
|
225
|
-
const dynamodb = new DynamoDB.DocumentClient();
|
|
226
|
-
|
|
227
|
-
exports.handler = async (event) => {
|
|
228
|
-
try {
|
|
229
|
-
const userId = event.pathParameters.userId;
|
|
230
|
-
|
|
231
|
-
const result = await dynamodb.get({
|
|
232
|
-
TableName: process.env.USERS_TABLE,
|
|
233
|
-
Key: { userId }
|
|
234
|
-
}).promise();
|
|
235
|
-
|
|
236
|
-
if (!result.Item) {
|
|
237
|
-
return {
|
|
238
|
-
statusCode: 404,
|
|
239
|
-
body: JSON.stringify({ error: 'User not found' })
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
statusCode: 200,
|
|
245
|
-
headers: {
|
|
246
|
-
'Content-Type': 'application/json',
|
|
247
|
-
'Access-Control-Allow-Origin': '*'
|
|
248
|
-
},
|
|
249
|
-
body: JSON.stringify(result.Item)
|
|
250
|
-
};
|
|
251
|
-
} catch (error) {
|
|
252
|
-
console.error('Error:', error);
|
|
253
|
-
return {
|
|
254
|
-
statusCode: 500,
|
|
255
|
-
body: JSON.stringify({ error: 'Internal server error' })
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
**Function: Create User**
|
|
262
|
-
```javascript
|
|
263
|
-
const { DynamoDB } = require('aws-sdk');
|
|
264
|
-
const { v4: uuidv4 } = require('uuid');
|
|
265
|
-
const dynamodb = new DynamoDB.DocumentClient();
|
|
266
|
-
|
|
267
|
-
exports.handler = async (event) => {
|
|
268
|
-
try {
|
|
269
|
-
const body = JSON.parse(event.body);
|
|
270
|
-
|
|
271
|
-
// Validate input
|
|
272
|
-
if (!body.email || !body.name) {
|
|
273
|
-
return {
|
|
274
|
-
statusCode: 400,
|
|
275
|
-
body: JSON.stringify({
|
|
276
|
-
error: 'Email and name are required'
|
|
277
|
-
})
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const user = {
|
|
282
|
-
userId: uuidv4(),
|
|
283
|
-
email: body.email,
|
|
284
|
-
name: body.name,
|
|
285
|
-
createdAt: new Date().toISOString()
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
await dynamodb.put({
|
|
289
|
-
TableName: process.env.USERS_TABLE,
|
|
290
|
-
Item: user
|
|
291
|
-
}).promise();
|
|
292
|
-
|
|
293
|
-
return {
|
|
294
|
-
statusCode: 201,
|
|
295
|
-
headers: {
|
|
296
|
-
'Content-Type': 'application/json',
|
|
297
|
-
'Access-Control-Allow-Origin': '*'
|
|
298
|
-
},
|
|
299
|
-
body: JSON.stringify(user)
|
|
300
|
-
};
|
|
301
|
-
} catch (error) {
|
|
302
|
-
console.error('Error:', error);
|
|
303
|
-
return {
|
|
304
|
-
statusCode: 500,
|
|
305
|
-
body: JSON.stringify({ error: 'Internal server error' })
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
**Infrastructure as Code (Serverless Framework)**
|
|
312
|
-
```yaml
|
|
313
|
-
service: user-api
|
|
314
|
-
|
|
315
|
-
provider:
|
|
316
|
-
name: aws
|
|
317
|
-
runtime: nodejs18.x
|
|
318
|
-
region: us-east-1
|
|
319
|
-
environment:
|
|
320
|
-
USERS_TABLE: ${self:service}-users-${self:provider.stage}
|
|
321
|
-
iamRoleStatements:
|
|
322
|
-
- Effect: Allow
|
|
323
|
-
Action:
|
|
324
|
-
- dynamodb:GetItem
|
|
325
|
-
- dynamodb:PutItem
|
|
326
|
-
- dynamodb:Query
|
|
327
|
-
Resource:
|
|
328
|
-
- arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.USERS_TABLE}
|
|
329
|
-
|
|
330
|
-
functions:
|
|
331
|
-
getUser:
|
|
332
|
-
handler: handlers/getUser.handler
|
|
333
|
-
events:
|
|
334
|
-
- http:
|
|
335
|
-
path: users/{userId}
|
|
336
|
-
method: get
|
|
337
|
-
cors: true
|
|
338
|
-
|
|
339
|
-
createUser:
|
|
340
|
-
handler: handlers/createUser.handler
|
|
341
|
-
events:
|
|
342
|
-
- http:
|
|
343
|
-
path: users
|
|
344
|
-
method: post
|
|
345
|
-
cors: true
|
|
346
|
-
|
|
347
|
-
resources:
|
|
348
|
-
Resources:
|
|
349
|
-
UsersTable:
|
|
350
|
-
Type: AWS::DynamoDB::Table
|
|
351
|
-
Properties:
|
|
352
|
-
TableName: ${self:provider.environment.USERS_TABLE}
|
|
353
|
-
AttributeDefinitions:
|
|
354
|
-
- AttributeName: userId
|
|
355
|
-
AttributeType: S
|
|
356
|
-
KeySchema:
|
|
357
|
-
- AttributeName: userId
|
|
358
|
-
KeyType: HASH
|
|
359
|
-
BillingMode: PAY_PER_REQUEST
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### Image Processing Pipeline
|
|
363
|
-
|
|
364
|
-
**S3 Trigger Function**
|
|
365
|
-
```javascript
|
|
366
|
-
const AWS = require('aws-sdk');
|
|
367
|
-
const sharp = require('sharp');
|
|
368
|
-
const s3 = new AWS.S3();
|
|
369
|
-
|
|
370
|
-
exports.handler = async (event) => {
|
|
371
|
-
// Get S3 event details
|
|
372
|
-
const bucket = event.Records[0].s3.bucket.name;
|
|
373
|
-
const key = decodeURIComponent(
|
|
374
|
-
event.Records[0].s3.object.key.replace(/\+/g, ' ')
|
|
375
|
-
);
|
|
376
|
-
|
|
377
|
-
try {
|
|
378
|
-
// Download image from S3
|
|
379
|
-
const image = await s3.getObject({
|
|
380
|
-
Bucket: bucket,
|
|
381
|
-
Key: key
|
|
382
|
-
}).promise();
|
|
383
|
-
|
|
384
|
-
// Resize image
|
|
385
|
-
const resized = await sharp(image.Body)
|
|
386
|
-
.resize(800, 600, { fit: 'inside' })
|
|
387
|
-
.jpeg({ quality: 80 })
|
|
388
|
-
.toBuffer();
|
|
389
|
-
|
|
390
|
-
// Upload resized image
|
|
391
|
-
const outputKey = key.replace('uploads/', 'thumbnails/');
|
|
392
|
-
await s3.putObject({
|
|
393
|
-
Bucket: bucket,
|
|
394
|
-
Key: outputKey,
|
|
395
|
-
Body: resized,
|
|
396
|
-
ContentType: 'image/jpeg'
|
|
397
|
-
}).promise();
|
|
398
|
-
|
|
399
|
-
console.log(`Resized ${key} to ${outputKey}`);
|
|
400
|
-
|
|
401
|
-
return {
|
|
402
|
-
statusCode: 200,
|
|
403
|
-
body: JSON.stringify({
|
|
404
|
-
message: 'Image processed successfully',
|
|
405
|
-
thumbnail: outputKey
|
|
406
|
-
})
|
|
407
|
-
};
|
|
408
|
-
} catch (error) {
|
|
409
|
-
console.error('Error processing image:', error);
|
|
410
|
-
throw error;
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
### Event-Driven Workflow with Step Functions
|
|
416
|
-
|
|
417
|
-
**Order Processing Workflow**
|
|
418
|
-
```json
|
|
419
|
-
{
|
|
420
|
-
"Comment": "Order processing workflow",
|
|
421
|
-
"StartAt": "ValidateOrder",
|
|
422
|
-
"States": {
|
|
423
|
-
"ValidateOrder": {
|
|
424
|
-
"Type": "Task",
|
|
425
|
-
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:ValidateOrder",
|
|
426
|
-
"Next": "CheckInventory"
|
|
427
|
-
},
|
|
428
|
-
"CheckInventory": {
|
|
429
|
-
"Type": "Task",
|
|
430
|
-
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:CheckInventory",
|
|
431
|
-
"Next": "InventoryAvailable?"
|
|
432
|
-
},
|
|
433
|
-
"InventoryAvailable?": {
|
|
434
|
-
"Type": "Choice",
|
|
435
|
-
"Choices": [
|
|
436
|
-
{
|
|
437
|
-
"Variable": "$.inventoryAvailable",
|
|
438
|
-
"BooleanEquals": true,
|
|
439
|
-
"Next": "ProcessPayment"
|
|
440
|
-
}
|
|
441
|
-
],
|
|
442
|
-
"Default": "NotifyOutOfStock"
|
|
443
|
-
},
|
|
444
|
-
"ProcessPayment": {
|
|
445
|
-
"Type": "Task",
|
|
446
|
-
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:ProcessPayment",
|
|
447
|
-
"Next": "PaymentSuccessful?"
|
|
448
|
-
},
|
|
449
|
-
"PaymentSuccessful?": {
|
|
450
|
-
"Type": "Choice",
|
|
451
|
-
"Choices": [
|
|
452
|
-
{
|
|
453
|
-
"Variable": "$.paymentStatus",
|
|
454
|
-
"StringEquals": "SUCCESS",
|
|
455
|
-
"Next": "FulfillOrder"
|
|
456
|
-
}
|
|
457
|
-
],
|
|
458
|
-
"Default": "NotifyPaymentFailed"
|
|
459
|
-
},
|
|
460
|
-
"FulfillOrder": {
|
|
461
|
-
"Type": "Task",
|
|
462
|
-
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:FulfillOrder",
|
|
463
|
-
"Next": "SendConfirmation"
|
|
464
|
-
},
|
|
465
|
-
"SendConfirmation": {
|
|
466
|
-
"Type": "Task",
|
|
467
|
-
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:SendConfirmation",
|
|
468
|
-
"End": true
|
|
469
|
-
},
|
|
470
|
-
"NotifyOutOfStock": {
|
|
471
|
-
"Type": "Task",
|
|
472
|
-
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:NotifyOutOfStock",
|
|
473
|
-
"End": true
|
|
474
|
-
},
|
|
475
|
-
"NotifyPaymentFailed": {
|
|
476
|
-
"Type": "Task",
|
|
477
|
-
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:NotifyPaymentFailed",
|
|
478
|
-
"End": true
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
**Lambda Function for Step**
|
|
485
|
-
```javascript
|
|
486
|
-
exports.handler = async (event) => {
|
|
487
|
-
const { orderId, items } = event;
|
|
488
|
-
|
|
489
|
-
// Check inventory
|
|
490
|
-
const inventoryAvailable = await checkInventory(items);
|
|
491
|
-
|
|
492
|
-
return {
|
|
493
|
-
...event,
|
|
494
|
-
inventoryAvailable,
|
|
495
|
-
checkedAt: new Date().toISOString()
|
|
496
|
-
};
|
|
497
|
-
};
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
### Scheduled Task (Cron Job)
|
|
501
|
-
|
|
502
|
-
**Daily Report Generator**
|
|
503
|
-
```javascript
|
|
504
|
-
const AWS = require('aws-sdk');
|
|
505
|
-
const s3 = new AWS.S3();
|
|
506
|
-
const dynamodb = new AWS.DynamoDB.DocumentClient();
|
|
507
|
-
|
|
508
|
-
exports.handler = async (event) => {
|
|
509
|
-
try {
|
|
510
|
-
// Get yesterday's date
|
|
511
|
-
const yesterday = new Date();
|
|
512
|
-
yesterday.setDate(yesterday.getDate() - 1);
|
|
513
|
-
const dateStr = yesterday.toISOString().split('T')[0];
|
|
514
|
-
|
|
515
|
-
// Query orders from yesterday
|
|
516
|
-
const orders = await dynamodb.query({
|
|
517
|
-
TableName: process.env.ORDERS_TABLE,
|
|
518
|
-
IndexName: 'DateIndex',
|
|
519
|
-
KeyConditionExpression: 'orderDate = :date',
|
|
520
|
-
ExpressionAttributeValues: {
|
|
521
|
-
':date': dateStr
|
|
522
|
-
}
|
|
523
|
-
}).promise();
|
|
524
|
-
|
|
525
|
-
// Generate report
|
|
526
|
-
const report = {
|
|
527
|
-
date: dateStr,
|
|
528
|
-
totalOrders: orders.Items.length,
|
|
529
|
-
totalRevenue: orders.Items.reduce(
|
|
530
|
-
(sum, order) => sum + order.total,
|
|
531
|
-
0
|
|
532
|
-
),
|
|
533
|
-
orders: orders.Items
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
// Save report to S3
|
|
537
|
-
await s3.putObject({
|
|
538
|
-
Bucket: process.env.REPORTS_BUCKET,
|
|
539
|
-
Key: `daily-reports/${dateStr}.json`,
|
|
540
|
-
Body: JSON.stringify(report, null, 2),
|
|
541
|
-
ContentType: 'application/json'
|
|
542
|
-
}).promise();
|
|
543
|
-
|
|
544
|
-
console.log(`Generated report for ${dateStr}`);
|
|
545
|
-
|
|
546
|
-
return {
|
|
547
|
-
statusCode: 200,
|
|
548
|
-
body: JSON.stringify({
|
|
549
|
-
message: 'Report generated successfully',
|
|
550
|
-
date: dateStr
|
|
551
|
-
})
|
|
552
|
-
};
|
|
553
|
-
} catch (error) {
|
|
554
|
-
console.error('Error generating report:', error);
|
|
555
|
-
throw error;
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
**CloudWatch Event Rule (Serverless Framework)**
|
|
561
|
-
```yaml
|
|
562
|
-
functions:
|
|
563
|
-
dailyReport:
|
|
564
|
-
handler: handlers/dailyReport.handler
|
|
565
|
-
events:
|
|
566
|
-
- schedule:
|
|
567
|
-
rate: cron(0 2 * * ? *) # Run at 2 AM UTC daily
|
|
568
|
-
enabled: true
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
---
|
|
572
|
-
|
|
573
|
-
## Understanding
|
|
574
|
-
|
|
575
|
-
### Advantages of Serverless Architecture
|
|
576
|
-
|
|
577
|
-
**No Server Management**
|
|
578
|
-
- No provisioning or maintenance
|
|
579
|
-
- Automatic OS updates
|
|
580
|
-
- Built-in high availability
|
|
581
|
-
- Focus on code, not infrastructure
|
|
582
|
-
|
|
583
|
-
**Automatic Scaling**
|
|
584
|
-
- Scales with demand
|
|
585
|
-
- Zero to thousands of requests
|
|
586
|
-
- No capacity planning
|
|
587
|
-
- Handles traffic spikes
|
|
588
|
-
|
|
589
|
-
**Cost Efficiency**
|
|
590
|
-
- Pay per execution
|
|
591
|
-
- No idle capacity costs
|
|
592
|
-
- Millisecond billing
|
|
593
|
-
- Free tier available
|
|
594
|
-
|
|
595
|
-
**Faster Time to Market**
|
|
596
|
-
- Rapid development
|
|
597
|
-
- Less operational overhead
|
|
598
|
-
- Built-in integrations
|
|
599
|
-
- Focus on business logic
|
|
600
|
-
|
|
601
|
-
**Built-in Fault Tolerance**
|
|
602
|
-
- Automatic retries
|
|
603
|
-
- Dead letter queues
|
|
604
|
-
- Multi-AZ deployment
|
|
605
|
-
- High availability
|
|
606
|
-
|
|
607
|
-
### Challenges and Disadvantages
|
|
608
|
-
|
|
609
|
-
**Cold Start Latency**
|
|
610
|
-
- First invocation delay (1-5 seconds)
|
|
611
|
-
- Impacts user experience
|
|
612
|
-
- Varies by runtime and package size
|
|
613
|
-
- Mitigated with provisioned concurrency (cost)
|
|
614
|
-
|
|
615
|
-
**Execution Time Limits**
|
|
616
|
-
- AWS Lambda: 15 minutes max
|
|
617
|
-
- Not suitable for long-running tasks
|
|
618
|
-
- Need to break into smaller functions
|
|
619
|
-
- Use Step Functions for orchestration
|
|
620
|
-
|
|
621
|
-
**Vendor Lock-in**
|
|
622
|
-
- Platform-specific APIs
|
|
623
|
-
- Migration complexity
|
|
624
|
-
- Limited portability
|
|
625
|
-
- Dependency on provider
|
|
626
|
-
|
|
627
|
-
**Debugging Challenges**
|
|
628
|
-
- Distributed system complexity
|
|
629
|
-
- Limited local testing
|
|
630
|
-
- CloudWatch logs only
|
|
631
|
-
- Difficult to reproduce issues
|
|
632
|
-
|
|
633
|
-
**Stateless Constraints**
|
|
634
|
-
- No persistent state in function
|
|
635
|
-
- External storage required
|
|
636
|
-
- Connection overhead
|
|
637
|
-
- Complexity for stateful apps
|
|
638
|
-
|
|
639
|
-
**Cost at Scale**
|
|
640
|
-
- Can be expensive at high volume
|
|
641
|
-
- Unpredictable costs
|
|
642
|
-
- Need monitoring and optimization
|
|
643
|
-
- Compare with container/VM costs
|
|
644
|
-
|
|
645
|
-
### Best Practices
|
|
646
|
-
|
|
647
|
-
**Function Design**
|
|
648
|
-
- Keep functions small and focused
|
|
649
|
-
- Minimize dependencies
|
|
650
|
-
- Optimize cold start time
|
|
651
|
-
- Use environment variables for configuration
|
|
652
|
-
- Implement proper error handling
|
|
653
|
-
|
|
654
|
-
**Security**
|
|
655
|
-
- Principle of least privilege (IAM)
|
|
656
|
-
- Encrypt sensitive data
|
|
657
|
-
- Use Secrets Manager for credentials
|
|
658
|
-
- Validate all inputs
|
|
659
|
-
- Enable VPC for private resources
|
|
660
|
-
|
|
661
|
-
**Performance**
|
|
662
|
-
- Reuse connections outside handler
|
|
663
|
-
- Use provisioned concurrency for critical paths
|
|
664
|
-
- Optimize package size
|
|
665
|
-
- Implement caching
|
|
666
|
-
- Monitor and optimize memory allocation
|
|
667
|
-
|
|
668
|
-
**Monitoring and Logging**
|
|
669
|
-
- Structured logging
|
|
670
|
-
- CloudWatch metrics
|
|
671
|
-
- Distributed tracing (X-Ray)
|
|
672
|
-
- Alerting on errors
|
|
673
|
-
- Cost monitoring
|
|
674
|
-
|
|
675
|
-
**Testing**
|
|
676
|
-
- Unit tests for business logic
|
|
677
|
-
- Integration tests with LocalStack
|
|
678
|
-
- Load testing
|
|
679
|
-
- Chaos engineering
|
|
680
|
-
- Canary deployments
|
|
681
|
-
|
|
682
|
-
---
|
|
683
|
-
|
|
684
|
-
## References
|
|
685
|
-
|
|
686
|
-
- **Books**
|
|
687
|
-
- "Serverless Architectures on AWS" by Peter Sbarski
|
|
688
|
-
- "AWS Lambda in Action" by Danilo Poccia
|
|
689
|
-
- "Serverless Design Patterns" by Brian Zambrano
|
|
690
|
-
|
|
691
|
-
- **Patterns**
|
|
692
|
-
- API Gateway Pattern
|
|
693
|
-
- Event-Driven Pattern
|
|
694
|
-
- Fan-Out Pattern
|
|
695
|
-
- Choreography Pattern
|
|
696
|
-
- Orchestration Pattern (Step Functions)
|
|
697
|
-
|
|
698
|
-
- **Platforms**
|
|
699
|
-
- AWS Lambda
|
|
700
|
-
- Azure Functions
|
|
701
|
-
- Google Cloud Functions
|
|
702
|
-
- Cloudflare Workers
|
|
703
|
-
- Vercel Functions
|
|
704
|
-
|
|
705
|
-
- **Frameworks**
|
|
706
|
-
- Serverless Framework
|
|
707
|
-
- AWS SAM (Serverless Application Model)
|
|
708
|
-
- Terraform
|
|
709
|
-
- Pulumi
|
|
710
|
-
|
|
711
|
-
|
|
1
|
+
# Serverless Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document covers serverless architecture patterns, Function-as-a-Service (FaaS), stateless functions, and best practices for building event-driven, scalable applications without managing servers.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Knowledge
|
|
10
|
+
|
|
11
|
+
### What is Serverless Architecture?
|
|
12
|
+
|
|
13
|
+
**Definition**
|
|
14
|
+
- Cloud execution model where provider manages infrastructure
|
|
15
|
+
- Code runs in stateless compute containers
|
|
16
|
+
- Event-driven execution
|
|
17
|
+
- Automatic scaling
|
|
18
|
+
- Pay-per-execution pricing
|
|
19
|
+
|
|
20
|
+
**Core Principles**
|
|
21
|
+
- No server management
|
|
22
|
+
- Stateless functions
|
|
23
|
+
- Event-driven triggers
|
|
24
|
+
- Automatic scaling
|
|
25
|
+
- Built-in high availability
|
|
26
|
+
|
|
27
|
+
**Serverless Components**
|
|
28
|
+
|
|
29
|
+
**FaaS (Function-as-a-Service)**
|
|
30
|
+
- AWS Lambda, Azure Functions, Google Cloud Functions
|
|
31
|
+
- Execute code in response to events
|
|
32
|
+
- Millisecond billing
|
|
33
|
+
- Automatic scaling
|
|
34
|
+
|
|
35
|
+
**BaaS (Backend-as-a-Service)**
|
|
36
|
+
- Managed services: databases, authentication, storage
|
|
37
|
+
- Examples: AWS DynamoDB, Firebase, Auth0
|
|
38
|
+
- No infrastructure management
|
|
39
|
+
|
|
40
|
+
**Characteristics**
|
|
41
|
+
- Ephemeral execution (short-lived)
|
|
42
|
+
- Stateless (no persistent state in function)
|
|
43
|
+
- Cold start latency
|
|
44
|
+
- Execution time limits (e.g., 15 min for Lambda)
|
|
45
|
+
- Memory and CPU limits
|
|
46
|
+
|
|
47
|
+
### When to Use Serverless
|
|
48
|
+
|
|
49
|
+
**Good Fit**
|
|
50
|
+
- Event-driven workloads
|
|
51
|
+
- Unpredictable or variable traffic
|
|
52
|
+
- Microservices and APIs
|
|
53
|
+
- Data processing pipelines
|
|
54
|
+
- Scheduled tasks (cron jobs)
|
|
55
|
+
- Webhooks and integrations
|
|
56
|
+
- Prototypes and MVPs
|
|
57
|
+
|
|
58
|
+
**Poor Fit**
|
|
59
|
+
- Long-running processes (> 15 minutes)
|
|
60
|
+
- Stateful applications
|
|
61
|
+
- Predictable, constant high load
|
|
62
|
+
- Low-latency requirements (< 100ms)
|
|
63
|
+
- Complex orchestration
|
|
64
|
+
- Legacy applications
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Skills
|
|
69
|
+
|
|
70
|
+
### Function Design
|
|
71
|
+
|
|
72
|
+
**Stateless Functions**
|
|
73
|
+
```javascript
|
|
74
|
+
// Good: Stateless function
|
|
75
|
+
exports.handler = async (event) => {
|
|
76
|
+
const userId = event.pathParameters.userId;
|
|
77
|
+
|
|
78
|
+
// Get data from external source
|
|
79
|
+
const user = await dynamodb.get({
|
|
80
|
+
TableName: 'Users',
|
|
81
|
+
Key: { userId }
|
|
82
|
+
}).promise();
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
statusCode: 200,
|
|
86
|
+
body: JSON.stringify(user.Item)
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Bad: Stateful function (don't do this)
|
|
91
|
+
let requestCount = 0; // State persists across invocations!
|
|
92
|
+
|
|
93
|
+
exports.handler = async (event) => {
|
|
94
|
+
requestCount++; // Unreliable
|
|
95
|
+
// ...
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Single Responsibility**
|
|
100
|
+
- One function, one purpose
|
|
101
|
+
- Small, focused functions
|
|
102
|
+
- Easy to test and maintain
|
|
103
|
+
- Independent deployment
|
|
104
|
+
|
|
105
|
+
**Function Size Guidelines**
|
|
106
|
+
- Keep functions small (< 500 lines)
|
|
107
|
+
- Minimize dependencies
|
|
108
|
+
- Fast cold start (< 3 seconds)
|
|
109
|
+
- Optimize package size
|
|
110
|
+
|
|
111
|
+
### Event Sources and Triggers
|
|
112
|
+
|
|
113
|
+
**HTTP Triggers**
|
|
114
|
+
- API Gateway → Lambda
|
|
115
|
+
- REST APIs
|
|
116
|
+
- Webhooks
|
|
117
|
+
- GraphQL endpoints
|
|
118
|
+
|
|
119
|
+
**Storage Triggers**
|
|
120
|
+
- S3 object created/deleted
|
|
121
|
+
- File processing
|
|
122
|
+
- Image resizing
|
|
123
|
+
- Data transformation
|
|
124
|
+
|
|
125
|
+
**Database Triggers**
|
|
126
|
+
- DynamoDB Streams
|
|
127
|
+
- Change data capture
|
|
128
|
+
- Audit logging
|
|
129
|
+
- Data replication
|
|
130
|
+
|
|
131
|
+
**Message Queue Triggers**
|
|
132
|
+
- SQS, SNS, EventBridge
|
|
133
|
+
- Asynchronous processing
|
|
134
|
+
- Event-driven workflows
|
|
135
|
+
- Decoupled systems
|
|
136
|
+
|
|
137
|
+
**Scheduled Triggers**
|
|
138
|
+
- CloudWatch Events (cron)
|
|
139
|
+
- Periodic tasks
|
|
140
|
+
- Batch processing
|
|
141
|
+
- Cleanup jobs
|
|
142
|
+
|
|
143
|
+
### Cold Start Optimization
|
|
144
|
+
|
|
145
|
+
**What is Cold Start?**
|
|
146
|
+
- First invocation after idle period
|
|
147
|
+
- Container initialization
|
|
148
|
+
- Code loading
|
|
149
|
+
- Dependency initialization
|
|
150
|
+
- Can add 1-5 seconds latency
|
|
151
|
+
|
|
152
|
+
**Optimization Techniques**
|
|
153
|
+
|
|
154
|
+
**Minimize Package Size**
|
|
155
|
+
```javascript
|
|
156
|
+
// Good: Import only what you need
|
|
157
|
+
const { DynamoDB } = require('aws-sdk');
|
|
158
|
+
|
|
159
|
+
// Bad: Import entire SDK
|
|
160
|
+
const AWS = require('aws-sdk');
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Lazy Loading**
|
|
164
|
+
```javascript
|
|
165
|
+
let dynamodb;
|
|
166
|
+
|
|
167
|
+
exports.handler = async (event) => {
|
|
168
|
+
// Initialize on first use
|
|
169
|
+
if (!dynamodb) {
|
|
170
|
+
const { DynamoDB } = require('aws-sdk');
|
|
171
|
+
dynamodb = new DynamoDB.DocumentClient();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Use dynamodb...
|
|
175
|
+
};
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Provisioned Concurrency**
|
|
179
|
+
- Keep functions warm
|
|
180
|
+
- Pre-initialized containers
|
|
181
|
+
- Eliminates cold starts
|
|
182
|
+
- Higher cost
|
|
183
|
+
|
|
184
|
+
**Connection Reuse**
|
|
185
|
+
```javascript
|
|
186
|
+
// Initialize outside handler (reused across invocations)
|
|
187
|
+
const { DynamoDB } = require('aws-sdk');
|
|
188
|
+
const dynamodb = new DynamoDB.DocumentClient();
|
|
189
|
+
|
|
190
|
+
exports.handler = async (event) => {
|
|
191
|
+
// Reuse connection
|
|
192
|
+
const result = await dynamodb.get({...}).promise();
|
|
193
|
+
return result;
|
|
194
|
+
};
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### State Management
|
|
198
|
+
|
|
199
|
+
**External State Storage**
|
|
200
|
+
- DynamoDB for NoSQL data
|
|
201
|
+
- RDS for relational data
|
|
202
|
+
- S3 for files and objects
|
|
203
|
+
- ElastiCache for caching
|
|
204
|
+
|
|
205
|
+
**Temporary State**
|
|
206
|
+
- /tmp directory (512 MB - 10 GB)
|
|
207
|
+
- Ephemeral (cleared between cold starts)
|
|
208
|
+
- Use for temporary files
|
|
209
|
+
|
|
210
|
+
**Distributed State**
|
|
211
|
+
- Step Functions for workflow state
|
|
212
|
+
- DynamoDB for shared state
|
|
213
|
+
- Parameter Store for configuration
|
|
214
|
+
- Secrets Manager for credentials
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Examples
|
|
219
|
+
|
|
220
|
+
### REST API with Lambda and API Gateway
|
|
221
|
+
|
|
222
|
+
**Function: Get User**
|
|
223
|
+
```javascript
|
|
224
|
+
const { DynamoDB } = require('aws-sdk');
|
|
225
|
+
const dynamodb = new DynamoDB.DocumentClient();
|
|
226
|
+
|
|
227
|
+
exports.handler = async (event) => {
|
|
228
|
+
try {
|
|
229
|
+
const userId = event.pathParameters.userId;
|
|
230
|
+
|
|
231
|
+
const result = await dynamodb.get({
|
|
232
|
+
TableName: process.env.USERS_TABLE,
|
|
233
|
+
Key: { userId }
|
|
234
|
+
}).promise();
|
|
235
|
+
|
|
236
|
+
if (!result.Item) {
|
|
237
|
+
return {
|
|
238
|
+
statusCode: 404,
|
|
239
|
+
body: JSON.stringify({ error: 'User not found' })
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
statusCode: 200,
|
|
245
|
+
headers: {
|
|
246
|
+
'Content-Type': 'application/json',
|
|
247
|
+
'Access-Control-Allow-Origin': '*'
|
|
248
|
+
},
|
|
249
|
+
body: JSON.stringify(result.Item)
|
|
250
|
+
};
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error('Error:', error);
|
|
253
|
+
return {
|
|
254
|
+
statusCode: 500,
|
|
255
|
+
body: JSON.stringify({ error: 'Internal server error' })
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Function: Create User**
|
|
262
|
+
```javascript
|
|
263
|
+
const { DynamoDB } = require('aws-sdk');
|
|
264
|
+
const { v4: uuidv4 } = require('uuid');
|
|
265
|
+
const dynamodb = new DynamoDB.DocumentClient();
|
|
266
|
+
|
|
267
|
+
exports.handler = async (event) => {
|
|
268
|
+
try {
|
|
269
|
+
const body = JSON.parse(event.body);
|
|
270
|
+
|
|
271
|
+
// Validate input
|
|
272
|
+
if (!body.email || !body.name) {
|
|
273
|
+
return {
|
|
274
|
+
statusCode: 400,
|
|
275
|
+
body: JSON.stringify({
|
|
276
|
+
error: 'Email and name are required'
|
|
277
|
+
})
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const user = {
|
|
282
|
+
userId: uuidv4(),
|
|
283
|
+
email: body.email,
|
|
284
|
+
name: body.name,
|
|
285
|
+
createdAt: new Date().toISOString()
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
await dynamodb.put({
|
|
289
|
+
TableName: process.env.USERS_TABLE,
|
|
290
|
+
Item: user
|
|
291
|
+
}).promise();
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
statusCode: 201,
|
|
295
|
+
headers: {
|
|
296
|
+
'Content-Type': 'application/json',
|
|
297
|
+
'Access-Control-Allow-Origin': '*'
|
|
298
|
+
},
|
|
299
|
+
body: JSON.stringify(user)
|
|
300
|
+
};
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error('Error:', error);
|
|
303
|
+
return {
|
|
304
|
+
statusCode: 500,
|
|
305
|
+
body: JSON.stringify({ error: 'Internal server error' })
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Infrastructure as Code (Serverless Framework)**
|
|
312
|
+
```yaml
|
|
313
|
+
service: user-api
|
|
314
|
+
|
|
315
|
+
provider:
|
|
316
|
+
name: aws
|
|
317
|
+
runtime: nodejs18.x
|
|
318
|
+
region: us-east-1
|
|
319
|
+
environment:
|
|
320
|
+
USERS_TABLE: ${self:service}-users-${self:provider.stage}
|
|
321
|
+
iamRoleStatements:
|
|
322
|
+
- Effect: Allow
|
|
323
|
+
Action:
|
|
324
|
+
- dynamodb:GetItem
|
|
325
|
+
- dynamodb:PutItem
|
|
326
|
+
- dynamodb:Query
|
|
327
|
+
Resource:
|
|
328
|
+
- arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.USERS_TABLE}
|
|
329
|
+
|
|
330
|
+
functions:
|
|
331
|
+
getUser:
|
|
332
|
+
handler: handlers/getUser.handler
|
|
333
|
+
events:
|
|
334
|
+
- http:
|
|
335
|
+
path: users/{userId}
|
|
336
|
+
method: get
|
|
337
|
+
cors: true
|
|
338
|
+
|
|
339
|
+
createUser:
|
|
340
|
+
handler: handlers/createUser.handler
|
|
341
|
+
events:
|
|
342
|
+
- http:
|
|
343
|
+
path: users
|
|
344
|
+
method: post
|
|
345
|
+
cors: true
|
|
346
|
+
|
|
347
|
+
resources:
|
|
348
|
+
Resources:
|
|
349
|
+
UsersTable:
|
|
350
|
+
Type: AWS::DynamoDB::Table
|
|
351
|
+
Properties:
|
|
352
|
+
TableName: ${self:provider.environment.USERS_TABLE}
|
|
353
|
+
AttributeDefinitions:
|
|
354
|
+
- AttributeName: userId
|
|
355
|
+
AttributeType: S
|
|
356
|
+
KeySchema:
|
|
357
|
+
- AttributeName: userId
|
|
358
|
+
KeyType: HASH
|
|
359
|
+
BillingMode: PAY_PER_REQUEST
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Image Processing Pipeline
|
|
363
|
+
|
|
364
|
+
**S3 Trigger Function**
|
|
365
|
+
```javascript
|
|
366
|
+
const AWS = require('aws-sdk');
|
|
367
|
+
const sharp = require('sharp');
|
|
368
|
+
const s3 = new AWS.S3();
|
|
369
|
+
|
|
370
|
+
exports.handler = async (event) => {
|
|
371
|
+
// Get S3 event details
|
|
372
|
+
const bucket = event.Records[0].s3.bucket.name;
|
|
373
|
+
const key = decodeURIComponent(
|
|
374
|
+
event.Records[0].s3.object.key.replace(/\+/g, ' ')
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
// Download image from S3
|
|
379
|
+
const image = await s3.getObject({
|
|
380
|
+
Bucket: bucket,
|
|
381
|
+
Key: key
|
|
382
|
+
}).promise();
|
|
383
|
+
|
|
384
|
+
// Resize image
|
|
385
|
+
const resized = await sharp(image.Body)
|
|
386
|
+
.resize(800, 600, { fit: 'inside' })
|
|
387
|
+
.jpeg({ quality: 80 })
|
|
388
|
+
.toBuffer();
|
|
389
|
+
|
|
390
|
+
// Upload resized image
|
|
391
|
+
const outputKey = key.replace('uploads/', 'thumbnails/');
|
|
392
|
+
await s3.putObject({
|
|
393
|
+
Bucket: bucket,
|
|
394
|
+
Key: outputKey,
|
|
395
|
+
Body: resized,
|
|
396
|
+
ContentType: 'image/jpeg'
|
|
397
|
+
}).promise();
|
|
398
|
+
|
|
399
|
+
console.log(`Resized ${key} to ${outputKey}`);
|
|
400
|
+
|
|
401
|
+
return {
|
|
402
|
+
statusCode: 200,
|
|
403
|
+
body: JSON.stringify({
|
|
404
|
+
message: 'Image processed successfully',
|
|
405
|
+
thumbnail: outputKey
|
|
406
|
+
})
|
|
407
|
+
};
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error('Error processing image:', error);
|
|
410
|
+
throw error;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Event-Driven Workflow with Step Functions
|
|
416
|
+
|
|
417
|
+
**Order Processing Workflow**
|
|
418
|
+
```json
|
|
419
|
+
{
|
|
420
|
+
"Comment": "Order processing workflow",
|
|
421
|
+
"StartAt": "ValidateOrder",
|
|
422
|
+
"States": {
|
|
423
|
+
"ValidateOrder": {
|
|
424
|
+
"Type": "Task",
|
|
425
|
+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:ValidateOrder",
|
|
426
|
+
"Next": "CheckInventory"
|
|
427
|
+
},
|
|
428
|
+
"CheckInventory": {
|
|
429
|
+
"Type": "Task",
|
|
430
|
+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:CheckInventory",
|
|
431
|
+
"Next": "InventoryAvailable?"
|
|
432
|
+
},
|
|
433
|
+
"InventoryAvailable?": {
|
|
434
|
+
"Type": "Choice",
|
|
435
|
+
"Choices": [
|
|
436
|
+
{
|
|
437
|
+
"Variable": "$.inventoryAvailable",
|
|
438
|
+
"BooleanEquals": true,
|
|
439
|
+
"Next": "ProcessPayment"
|
|
440
|
+
}
|
|
441
|
+
],
|
|
442
|
+
"Default": "NotifyOutOfStock"
|
|
443
|
+
},
|
|
444
|
+
"ProcessPayment": {
|
|
445
|
+
"Type": "Task",
|
|
446
|
+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:ProcessPayment",
|
|
447
|
+
"Next": "PaymentSuccessful?"
|
|
448
|
+
},
|
|
449
|
+
"PaymentSuccessful?": {
|
|
450
|
+
"Type": "Choice",
|
|
451
|
+
"Choices": [
|
|
452
|
+
{
|
|
453
|
+
"Variable": "$.paymentStatus",
|
|
454
|
+
"StringEquals": "SUCCESS",
|
|
455
|
+
"Next": "FulfillOrder"
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
"Default": "NotifyPaymentFailed"
|
|
459
|
+
},
|
|
460
|
+
"FulfillOrder": {
|
|
461
|
+
"Type": "Task",
|
|
462
|
+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:FulfillOrder",
|
|
463
|
+
"Next": "SendConfirmation"
|
|
464
|
+
},
|
|
465
|
+
"SendConfirmation": {
|
|
466
|
+
"Type": "Task",
|
|
467
|
+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:SendConfirmation",
|
|
468
|
+
"End": true
|
|
469
|
+
},
|
|
470
|
+
"NotifyOutOfStock": {
|
|
471
|
+
"Type": "Task",
|
|
472
|
+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:NotifyOutOfStock",
|
|
473
|
+
"End": true
|
|
474
|
+
},
|
|
475
|
+
"NotifyPaymentFailed": {
|
|
476
|
+
"Type": "Task",
|
|
477
|
+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:NotifyPaymentFailed",
|
|
478
|
+
"End": true
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
**Lambda Function for Step**
|
|
485
|
+
```javascript
|
|
486
|
+
exports.handler = async (event) => {
|
|
487
|
+
const { orderId, items } = event;
|
|
488
|
+
|
|
489
|
+
// Check inventory
|
|
490
|
+
const inventoryAvailable = await checkInventory(items);
|
|
491
|
+
|
|
492
|
+
return {
|
|
493
|
+
...event,
|
|
494
|
+
inventoryAvailable,
|
|
495
|
+
checkedAt: new Date().toISOString()
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Scheduled Task (Cron Job)
|
|
501
|
+
|
|
502
|
+
**Daily Report Generator**
|
|
503
|
+
```javascript
|
|
504
|
+
const AWS = require('aws-sdk');
|
|
505
|
+
const s3 = new AWS.S3();
|
|
506
|
+
const dynamodb = new AWS.DynamoDB.DocumentClient();
|
|
507
|
+
|
|
508
|
+
exports.handler = async (event) => {
|
|
509
|
+
try {
|
|
510
|
+
// Get yesterday's date
|
|
511
|
+
const yesterday = new Date();
|
|
512
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
513
|
+
const dateStr = yesterday.toISOString().split('T')[0];
|
|
514
|
+
|
|
515
|
+
// Query orders from yesterday
|
|
516
|
+
const orders = await dynamodb.query({
|
|
517
|
+
TableName: process.env.ORDERS_TABLE,
|
|
518
|
+
IndexName: 'DateIndex',
|
|
519
|
+
KeyConditionExpression: 'orderDate = :date',
|
|
520
|
+
ExpressionAttributeValues: {
|
|
521
|
+
':date': dateStr
|
|
522
|
+
}
|
|
523
|
+
}).promise();
|
|
524
|
+
|
|
525
|
+
// Generate report
|
|
526
|
+
const report = {
|
|
527
|
+
date: dateStr,
|
|
528
|
+
totalOrders: orders.Items.length,
|
|
529
|
+
totalRevenue: orders.Items.reduce(
|
|
530
|
+
(sum, order) => sum + order.total,
|
|
531
|
+
0
|
|
532
|
+
),
|
|
533
|
+
orders: orders.Items
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
// Save report to S3
|
|
537
|
+
await s3.putObject({
|
|
538
|
+
Bucket: process.env.REPORTS_BUCKET,
|
|
539
|
+
Key: `daily-reports/${dateStr}.json`,
|
|
540
|
+
Body: JSON.stringify(report, null, 2),
|
|
541
|
+
ContentType: 'application/json'
|
|
542
|
+
}).promise();
|
|
543
|
+
|
|
544
|
+
console.log(`Generated report for ${dateStr}`);
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
statusCode: 200,
|
|
548
|
+
body: JSON.stringify({
|
|
549
|
+
message: 'Report generated successfully',
|
|
550
|
+
date: dateStr
|
|
551
|
+
})
|
|
552
|
+
};
|
|
553
|
+
} catch (error) {
|
|
554
|
+
console.error('Error generating report:', error);
|
|
555
|
+
throw error;
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**CloudWatch Event Rule (Serverless Framework)**
|
|
561
|
+
```yaml
|
|
562
|
+
functions:
|
|
563
|
+
dailyReport:
|
|
564
|
+
handler: handlers/dailyReport.handler
|
|
565
|
+
events:
|
|
566
|
+
- schedule:
|
|
567
|
+
rate: cron(0 2 * * ? *) # Run at 2 AM UTC daily
|
|
568
|
+
enabled: true
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## Understanding
|
|
574
|
+
|
|
575
|
+
### Advantages of Serverless Architecture
|
|
576
|
+
|
|
577
|
+
**No Server Management**
|
|
578
|
+
- No provisioning or maintenance
|
|
579
|
+
- Automatic OS updates
|
|
580
|
+
- Built-in high availability
|
|
581
|
+
- Focus on code, not infrastructure
|
|
582
|
+
|
|
583
|
+
**Automatic Scaling**
|
|
584
|
+
- Scales with demand
|
|
585
|
+
- Zero to thousands of requests
|
|
586
|
+
- No capacity planning
|
|
587
|
+
- Handles traffic spikes
|
|
588
|
+
|
|
589
|
+
**Cost Efficiency**
|
|
590
|
+
- Pay per execution
|
|
591
|
+
- No idle capacity costs
|
|
592
|
+
- Millisecond billing
|
|
593
|
+
- Free tier available
|
|
594
|
+
|
|
595
|
+
**Faster Time to Market**
|
|
596
|
+
- Rapid development
|
|
597
|
+
- Less operational overhead
|
|
598
|
+
- Built-in integrations
|
|
599
|
+
- Focus on business logic
|
|
600
|
+
|
|
601
|
+
**Built-in Fault Tolerance**
|
|
602
|
+
- Automatic retries
|
|
603
|
+
- Dead letter queues
|
|
604
|
+
- Multi-AZ deployment
|
|
605
|
+
- High availability
|
|
606
|
+
|
|
607
|
+
### Challenges and Disadvantages
|
|
608
|
+
|
|
609
|
+
**Cold Start Latency**
|
|
610
|
+
- First invocation delay (1-5 seconds)
|
|
611
|
+
- Impacts user experience
|
|
612
|
+
- Varies by runtime and package size
|
|
613
|
+
- Mitigated with provisioned concurrency (cost)
|
|
614
|
+
|
|
615
|
+
**Execution Time Limits**
|
|
616
|
+
- AWS Lambda: 15 minutes max
|
|
617
|
+
- Not suitable for long-running tasks
|
|
618
|
+
- Need to break into smaller functions
|
|
619
|
+
- Use Step Functions for orchestration
|
|
620
|
+
|
|
621
|
+
**Vendor Lock-in**
|
|
622
|
+
- Platform-specific APIs
|
|
623
|
+
- Migration complexity
|
|
624
|
+
- Limited portability
|
|
625
|
+
- Dependency on provider
|
|
626
|
+
|
|
627
|
+
**Debugging Challenges**
|
|
628
|
+
- Distributed system complexity
|
|
629
|
+
- Limited local testing
|
|
630
|
+
- CloudWatch logs only
|
|
631
|
+
- Difficult to reproduce issues
|
|
632
|
+
|
|
633
|
+
**Stateless Constraints**
|
|
634
|
+
- No persistent state in function
|
|
635
|
+
- External storage required
|
|
636
|
+
- Connection overhead
|
|
637
|
+
- Complexity for stateful apps
|
|
638
|
+
|
|
639
|
+
**Cost at Scale**
|
|
640
|
+
- Can be expensive at high volume
|
|
641
|
+
- Unpredictable costs
|
|
642
|
+
- Need monitoring and optimization
|
|
643
|
+
- Compare with container/VM costs
|
|
644
|
+
|
|
645
|
+
### Best Practices
|
|
646
|
+
|
|
647
|
+
**Function Design**
|
|
648
|
+
- Keep functions small and focused
|
|
649
|
+
- Minimize dependencies
|
|
650
|
+
- Optimize cold start time
|
|
651
|
+
- Use environment variables for configuration
|
|
652
|
+
- Implement proper error handling
|
|
653
|
+
|
|
654
|
+
**Security**
|
|
655
|
+
- Principle of least privilege (IAM)
|
|
656
|
+
- Encrypt sensitive data
|
|
657
|
+
- Use Secrets Manager for credentials
|
|
658
|
+
- Validate all inputs
|
|
659
|
+
- Enable VPC for private resources
|
|
660
|
+
|
|
661
|
+
**Performance**
|
|
662
|
+
- Reuse connections outside handler
|
|
663
|
+
- Use provisioned concurrency for critical paths
|
|
664
|
+
- Optimize package size
|
|
665
|
+
- Implement caching
|
|
666
|
+
- Monitor and optimize memory allocation
|
|
667
|
+
|
|
668
|
+
**Monitoring and Logging**
|
|
669
|
+
- Structured logging
|
|
670
|
+
- CloudWatch metrics
|
|
671
|
+
- Distributed tracing (X-Ray)
|
|
672
|
+
- Alerting on errors
|
|
673
|
+
- Cost monitoring
|
|
674
|
+
|
|
675
|
+
**Testing**
|
|
676
|
+
- Unit tests for business logic
|
|
677
|
+
- Integration tests with LocalStack
|
|
678
|
+
- Load testing
|
|
679
|
+
- Chaos engineering
|
|
680
|
+
- Canary deployments
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## References
|
|
685
|
+
|
|
686
|
+
- **Books**
|
|
687
|
+
- "Serverless Architectures on AWS" by Peter Sbarski
|
|
688
|
+
- "AWS Lambda in Action" by Danilo Poccia
|
|
689
|
+
- "Serverless Design Patterns" by Brian Zambrano
|
|
690
|
+
|
|
691
|
+
- **Patterns**
|
|
692
|
+
- API Gateway Pattern
|
|
693
|
+
- Event-Driven Pattern
|
|
694
|
+
- Fan-Out Pattern
|
|
695
|
+
- Choreography Pattern
|
|
696
|
+
- Orchestration Pattern (Step Functions)
|
|
697
|
+
|
|
698
|
+
- **Platforms**
|
|
699
|
+
- AWS Lambda
|
|
700
|
+
- Azure Functions
|
|
701
|
+
- Google Cloud Functions
|
|
702
|
+
- Cloudflare Workers
|
|
703
|
+
- Vercel Functions
|
|
704
|
+
|
|
705
|
+
- **Frameworks**
|
|
706
|
+
- Serverless Framework
|
|
707
|
+
- AWS SAM (Serverless Application Model)
|
|
708
|
+
- Terraform
|
|
709
|
+
- Pulumi
|
|
710
|
+
|
|
711
|
+
|