Last active
November 10, 2023 19:23
-
-
Save PatrickJS/ff8dd91439451fc17b5850ab1b19923e to your computer and use it in GitHub Desktop.
versioned lambdas in s3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import * as https from 'https'; | |
| import { NodeHttpHandler } from '@aws-sdk/node-http-handler'; | |
| import { promises as fs } from 'fs'; | |
| import path from 'path'; | |
| import { S3Client, GetObjectCommand, ListObjectsV2Command } from '@aws-sdk/client-s3'; | |
| // Create an HTTPS agent with keep-alive enabled | |
| const keepAliveAgent = new https.Agent({ | |
| keepAlive: true, | |
| maxSockets: 50, // Maximum number of sockets to allow per host | |
| maxFreeSockets: 10, // Maximum number of sockets to leave open in a free state | |
| timeout: 60000, // Socket idle timeout | |
| freeSocketTimeout: 30000 // Free socket keep-alive for 30 seconds | |
| }); | |
| // Initialize the S3 client for the us-east-1 region | |
| const s3 = new S3Client({ | |
| region: <--s3-region-->, | |
| requestHandler: new NodeHttpHandler({ | |
| httpsAgent: keepAliveAgent | |
| }) | |
| }); | |
| const BUCKET_NAME = <--Bucket-->; | |
| // Helper function to download a file from S3 | |
| async function downloadFileFromS3(bucket, key, localPath) { | |
| // Skip if key is a directory | |
| if (!key.endsWith('/')) { | |
| const command = new GetObjectCommand({ Bucket: bucket, Key: key }); | |
| const data = await s3.send(command); | |
| // Ensure the directory structure is present | |
| await fs.mkdir(path.dirname(localPath), { recursive: true }); | |
| // Write the data to a local file | |
| await fs.writeFile(localPath, data.Body); | |
| } | |
| } | |
| // Helper function to list files under a specific S3 prefix | |
| async function listFiles(bucket, prefix) { | |
| const command = new ListObjectsV2Command({ Bucket: bucket, Prefix: prefix }); | |
| const data = await s3.send(command); | |
| return data.Contents.map(content => content.Key); | |
| } | |
| // Helper function to download all files for a specific version prefix | |
| async function downloadVersionedFiles(bucket, versionPrefix) { | |
| const files = await listFiles(bucket, versionPrefix); | |
| for (const fileKey of files) { | |
| if (!fileKey.endsWith('/')) { // Skip directories | |
| const localPath = path.join('/tmp', fileKey); | |
| await downloadFileFromS3(bucket, fileKey, localPath); | |
| } | |
| } | |
| } | |
| // Lambda handler function | |
| export const handler = async (event) => { | |
| const rawPath = event.rawPath; | |
| const pathParts = rawPath.split('/').filter(Boolean); // Splits and removes empty strings | |
| // Validate the path structure | |
| if (pathParts.length < 4) { | |
| return { statusCode: 400, body: 'Invalid path. Expected format: /org/repo/version/filename.js' }; | |
| } | |
| // Extract path components | |
| const [org, repo, version, ...rest] = pathParts; | |
| const filename = rest.join('/'); | |
| const versionPrefix = `${org}/${repo}/${version}/`; | |
| try { | |
| // Download files from the specified versioned S3 path | |
| await downloadVersionedFiles(BUCKET_NAME, versionPrefix); | |
| const filePath = path.join('/tmp', versionPrefix, filename); | |
| // Check if the file exists and is not a directory | |
| try { | |
| await fs.access(filePath); | |
| } catch { | |
| return { statusCode: 404, body: 'File not found.' }; | |
| } | |
| // Dynamically import the module from the local file | |
| // make sure to have package.json in the directory with { type: "module" } | |
| const module = await import(filePath); | |
| // Execute the module's default export if it exists | |
| if (module.default) { | |
| const result = await module.default(event); | |
| return { statusCode: 200, body: JSON.stringify(result) }; | |
| } else { | |
| return { statusCode: 500, body: 'No default export found in module.' }; | |
| } | |
| } catch (error) { | |
| console.error('Error:', error); | |
| return { statusCode: 500, body: JSON.stringify({ message: 'Execution failed', error: error.message }) }; | |
| } | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment