Skip to content

Commit 2680cab

Browse files
committed
Added examples
1 parent fdc9760 commit 2680cab

File tree

5 files changed

+641
-1
lines changed

5 files changed

+641
-1
lines changed

README.md

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,183 @@ npm run deploy-force 1.0.1
138138

139139
# Using the @hopdrive/package-deploy-scripts integration
140140
npm run deploy-wrapper # Uses the wrapper around package-deploy-scripts
141-
npm run deploy:wrapper # Uses direct integration with package-deploy-scripts
142141
```
143142

143+
During deployment, the `lib/version.js` file is automatically generated using the `genversion` npm package. This file exports the current package version from package.json, making it accessible throughout the codebase.
144+
145+
## Examples
146+
147+
This package includes several example implementations in the `examples` directory:
148+
149+
### 1. Simple Lambda Example
150+
151+
**File:** `examples/simple-lambda-example.js`
152+
153+
A basic example showing how to use the wrapper in a standard AWS Lambda function without any framework dependencies.
154+
155+
### 2. Netlify Function Example
156+
157+
**Files:**
158+
- JavaScript: `examples/netlify-function-example.js`
159+
- TypeScript: `examples/netlify-function-example.ts`
160+
161+
Shows how to use the wrapper in a Netlify Function, which runs on AWS Lambda, with database connection handling.
162+
163+
### 3. Local Testing Example
164+
165+
**File:** `examples/local-fallback-example.js`
166+
167+
Demonstrates how to use the wrapper with the fallback timer mode for local development and testing outside of a Lambda environment.
168+
169+
### How to Use These Examples
170+
171+
#### AWS Lambda or Netlify Functions
172+
173+
1. **Install the package:**
174+
```bash
175+
npm install @hopdrive/lambda-timeout-wrapper
176+
```
177+
178+
2. **For Netlify Functions:**
179+
- Create a `netlify/functions` directory in your project
180+
- Copy the example file and customize as needed
181+
- Install TypeScript if using the TypeScript example:
182+
```bash
183+
npm install --save-dev typescript @netlify/functions
184+
```
185+
- Create a `netlify.toml` file to configure function settings:
186+
```toml
187+
[build]
188+
functions = "netlify/functions"
189+
190+
[functions]
191+
# Extend the timeout to 30 seconds (default is 10)
192+
timeout = 30
193+
```
194+
195+
3. **Deploy to AWS or Netlify:**
196+
- Follow standard AWS Lambda or Netlify deployment procedures
197+
- Your functions will now gracefully handle timeouts
198+
199+
#### Local Testing
200+
201+
1. **Install the package:**
202+
```bash
203+
npm install @hopdrive/lambda-timeout-wrapper
204+
```
205+
206+
2. **Run the local example:**
207+
```bash
208+
node examples/local-fallback-example.js
209+
```
210+
211+
3. **Customize timeout values:**
212+
- Adjust `getRemainingTimeInMillis` to simulate different Lambda timeouts
213+
- Modify the simulated task duration to test timeout behavior
214+
215+
### Key Concepts Demonstrated
216+
217+
#### 1. Creating the Wrapper
218+
219+
```javascript
220+
const wrapper = createTimeoutWrapper({
221+
// Get remaining time from Lambda context (for Lambda/Netlify)
222+
getRemainingTimeInMillis: context.getRemainingTimeInMillis,
223+
// OR use fallback timer for local testing
224+
// isUsingFallbackTimer: true,
225+
// getRemainingTimeInMillis: () => 10000, // 10 seconds
226+
227+
// Set safety margin (how early to detect timeout)
228+
safetyMarginMs: 3000, // 3 seconds
229+
230+
// Enable logging
231+
logger: console.log
232+
});
233+
```
234+
235+
#### 2. Using the Wrapper
236+
237+
```javascript
238+
const result = await wrapper(
239+
// Main function - your primary logic
240+
async () => {
241+
// Do your work here
242+
return { success: true };
243+
},
244+
245+
// Timeout handler - runs when timeout is imminent
246+
async () => {
247+
// Handle timeout gracefully
248+
return { timedOut: true };
249+
},
250+
251+
// User cleanup handler - always runs after success or timeout
252+
async () => {
253+
// Clean up resources here (database connections, etc.)
254+
}
255+
);
256+
```
257+
258+
#### 3. Error Handling
259+
260+
```javascript
261+
try {
262+
const result = await wrapper(/* ... */);
263+
return result;
264+
} catch (error) {
265+
// Check if it's a timeout error
266+
if (error.isLambdaTimeout) {
267+
// Handle timeout-specific error case
268+
}
269+
270+
// Handle other errors
271+
}
272+
```
273+
274+
### Implementation Details for Netlify Functions
275+
276+
1. **Directory Structure:**
277+
```
278+
your-project/
279+
├── netlify.toml
280+
└── netlify/
281+
└── functions/
282+
└── your-function.js
283+
```
284+
285+
2. **Required Dependencies:**
286+
- For JavaScript:
287+
```bash
288+
npm install @hopdrive/lambda-timeout-wrapper
289+
```
290+
- For TypeScript:
291+
```bash
292+
npm install @hopdrive/lambda-timeout-wrapper
293+
npm install --save-dev typescript @netlify/functions @types/node
294+
```
295+
296+
3. **Running Locally:**
297+
```bash
298+
npm install -g netlify-cli
299+
netlify dev
300+
```
301+
302+
4. **Testing:**
303+
Access your function at: `http://localhost:8888/.netlify/functions/your-function`
304+
305+
### Testing Timeout Behavior
306+
307+
To test timeout behavior:
308+
309+
1. **Increase task duration:**
310+
- Modify the setTimeout duration in the examples to exceed the timeout limit
311+
312+
2. **Decrease safety margin:**
313+
- Set a smaller safetyMarginMs value to test different cleanup timing
314+
315+
3. **Observe graceful shutdown:**
316+
- Watch how resources are properly cleaned up when timeout occurs
317+
144318
## License
145319
146320
MIT

examples/local-fallback-example.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Local testing example using lambda-timeout-wrapper with fallback timer
3+
*
4+
* This example demonstrates how to use the wrapper outside of an AWS Lambda environment
5+
* using the fallback timer mode for local development and testing.
6+
*/
7+
8+
const { createTimeoutWrapper } = require('@hopdrive/lambda-timeout-wrapper');
9+
10+
// This function demonstrates how to test the timeout wrapper locally
11+
async function runLocalTest() {
12+
console.log('Starting local test with fallback timer');
13+
14+
// Create a wrapper with fallback timer mode
15+
// (no Lambda context is needed)
16+
const wrapper = createTimeoutWrapper({
17+
// Enable fallback timer mode
18+
isUsingFallbackTimer: true,
19+
20+
// Set a fixed time limit (10 seconds in this example)
21+
getRemainingTimeInMillis: () => 10000,
22+
23+
// Set a 2 second safety margin
24+
safetyMarginMs: 2000,
25+
26+
// Log messages
27+
logger: console.log
28+
});
29+
30+
try {
31+
// Use the wrapper
32+
const result = await wrapper(
33+
// Main function - this will either complete or time out
34+
async () => {
35+
console.log('Main function started');
36+
37+
// Simulate a long-running task
38+
console.log('Running task for 9 seconds...');
39+
await new Promise(resolve => setTimeout(resolve, 9000));
40+
41+
// This will execute if we don't time out
42+
console.log('Task completed');
43+
return 'Success! Task completed within time limit';
44+
},
45+
46+
// Timeout handler - runs when a timeout is detected
47+
async () => {
48+
console.log('Timeout detected!');
49+
return 'Timeout occurred - handled gracefully';
50+
},
51+
52+
// User cleanup handler - optional but should be included for proper usage
53+
async () => {
54+
console.log('Cleanup handler called - this always runs');
55+
// Add cleanup logic here
56+
}
57+
);
58+
59+
console.log('Result:', result);
60+
return result;
61+
}
62+
catch (error) {
63+
console.error('Error during execution:', error);
64+
throw error;
65+
}
66+
}
67+
68+
// Run the example if this file is executed directly
69+
if (require.main === module) {
70+
runLocalTest()
71+
.then(result => {
72+
console.log('Test completed with result:', result);
73+
})
74+
.catch(error => {
75+
console.error('Test failed with error:', error);
76+
process.exit(1);
77+
});
78+
}
79+
80+
// Export for use in other modules
81+
module.exports = { runLocalTest };

examples/netlify-function-example.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* Example Netlify function that demonstrates using lambda-timeout-wrapper
3+
*
4+
* This example shows how to:
5+
* 1. Create a timeout wrapper with appropriate configuration
6+
* 2. Implement a main function with long-running operations
7+
* 3. Add timeout and cleanup handlers
8+
* 4. Handle the response appropriately
9+
*/
10+
11+
const { createTimeoutWrapper } = require('@hopdrive/lambda-timeout-wrapper');
12+
13+
// Example of a database connection that would need cleanup
14+
let dbConnection = null;
15+
16+
// Simulates connecting to a database
17+
const connectToDatabase = async () => {
18+
console.log('Connecting to database...');
19+
// Simulate connection delay
20+
await new Promise(resolve => setTimeout(resolve, 1000));
21+
dbConnection = {
22+
isConnected: true,
23+
close: async () => {
24+
console.log('Database connection closed gracefully');
25+
dbConnection = null;
26+
}
27+
};
28+
console.log('Connected to database');
29+
return dbConnection;
30+
};
31+
32+
// Simulates a long-running database query
33+
const runLongQuery = async () => {
34+
console.log('Running long database query...');
35+
// Simulate a long-running operation
36+
await new Promise(resolve => setTimeout(resolve, 5000));
37+
console.log('Query completed');
38+
return { results: ['item1', 'item2', 'item3'] };
39+
};
40+
41+
// Main Netlify function handler
42+
exports.handler = async (event, context) => {
43+
// Create timeout wrapper with Lambda context
44+
const wrapper = createTimeoutWrapper({
45+
// Get remaining time from Lambda context
46+
getRemainingTimeInMillis: () => context.getRemainingTimeInMillis(),
47+
// Set a 3-second safety margin (default is 5000ms)
48+
safetyMarginMs: 3000,
49+
// Log messages for debugging
50+
logger: console.log
51+
});
52+
53+
try {
54+
// Use the wrapper around your function execution
55+
const result = await wrapper(
56+
// Main function - this is where your primary logic goes
57+
async () => {
58+
// Connect to the database
59+
await connectToDatabase();
60+
61+
// Run a long query that might timeout
62+
const queryResults = await runLongQuery();
63+
64+
// Process results
65+
return {
66+
statusCode: 200,
67+
body: JSON.stringify({
68+
message: 'Operation completed successfully',
69+
data: queryResults
70+
})
71+
};
72+
},
73+
74+
// Timeout handler - runs when timeout is imminent
75+
async () => {
76+
console.log('TIMEOUT IMMINENT: Beginning graceful shutdown...');
77+
// Add any critical cleanup operations here
78+
79+
// Return a timeout response to the client
80+
return {
81+
statusCode: 408,
82+
body: JSON.stringify({
83+
message: 'Request timeout',
84+
error: 'The operation took too long to complete'
85+
})
86+
};
87+
},
88+
89+
// User cleanup handler - always runs after either success or timeout
90+
async () => {
91+
// Close database connection if it exists
92+
if (dbConnection && dbConnection.isConnected) {
93+
await dbConnection.close();
94+
}
95+
}
96+
);
97+
98+
// Return the result from the main function
99+
return result;
100+
}
101+
catch (error) {
102+
console.error('Error in Lambda function:', error);
103+
104+
// Check if it's a timeout error
105+
if (error.isLambdaTimeout) {
106+
return {
107+
statusCode: 408,
108+
body: JSON.stringify({
109+
message: 'Request timeout',
110+
error: 'The operation took too long to complete'
111+
})
112+
};
113+
}
114+
115+
// Handle other errors
116+
return {
117+
statusCode: 500,
118+
body: JSON.stringify({
119+
message: 'Internal server error',
120+
error: error.message
121+
})
122+
};
123+
}
124+
};

0 commit comments

Comments
 (0)