Quiero devolver una secuencia de una función para que el controlador principal de Lambda cree una canalización. Esto funciona:
const { S3Client } = require("@aws-sdk/client-s3") const { Upload } = require('@aws-sdk/lib-storage') const stream = require('stream') const s3Region = 'us-east-1' const bucketname = "my_bucket" exports.handler = function (event, context, callback) { let streamfrom = stream.Readable.from(["four"]) getS3Stream() .then(streamto => { stream.pipeline( streamfrom, streamto, () => { callback(null, { 'statusCode': 200 }) }) }) } function getS3Stream() { return new Promise(resolve => { const pass = new stream.PassThrough() const upload = new Upload({ client: new S3Client({ region: s3Region }), params: { Bucket: bucketname, Key: "test/test.txt", Body: pass } }) upload.done().then((res, error) => { if (error) { reject(error) } console.log("s3 uploaded") }) resolve(pass) }) }Pero quiero que la función del controlador devuelva una promesa en lugar de usar una devolución de llamada, momento en el que ya no funciona:
exports.handler = async function (event, context) { return new Promise(resolve => { let streamfrom = stream.Readable.from(["five5"]) getS3Stream() .then(streamto => { stream.pipeline( streamfrom, streamto, () => { resolve({ 'statusCode': 200 }) }) }) }) }Devuelve {"statusCode":200}, pero "s3 uploaded" no se imprime y el archivo no aparece en S3. ¿Estoy malinterpretando algo sobre cómo usar las promesas aquí?
Si desea que su controlador devuelva una Promesa, debe marcarlo como async .
No he encontrado ninguna documentación sobre esto, pero creo que la persona que llama en tiempo de ejecución primero verifica la definición del controlador para saber cómo debe llamarlo.
Algo como:
if (handler.constructor.name === 'AsyncFunction') { result = await handler(event, context) handleResult(null, result) } else if (handler.constructor.name === 'Function') { handler(event, context, handleResult) } else {}Entonces, volviendo a su código original, puede ser simplemente
exports.handler = async function (event, context) { return new Promise(resolve => { let streamfrom = stream.Readable.from(["five5"]) getS3Stream() .then(streamto => { stream.pipeline( streamfrom, streamto, () => resolve({'statusCode': 200}) ) }) }) } function getS3Stream() { return new Promise(resolve => { const pass = new stream.PassThrough() const upload = new Upload({ client: new S3Client({region: s3Region}), params: { Bucket: bucketname, Key: "test/test.txt", Body: pass } }) upload.done().then((res, error) => { if (error) { reject(error) } console.log("s3 uploaded") resolve(pass) }) }) }Inspirado por esto , se me ocurrió una solución que casi cumple con mis calificaciones. La función no devuelve solo el flujo, también devuelve la promesa. Todavía espero que a alguien se le ocurra algo que funcione sin esa muleta.
const { S3Client } = require("@aws-sdk/client-s3") const { Upload } = require('@aws-sdk/lib-storage') const stream = require('stream'); const s3Region = 'us-east-1' const bucketname = "my_bucket" exports.handler = async function (event, context) { return new Promise(resolve => { let streamfrom = stream.Readable.from(["five5"]) getS3Stream() .then(({streamto, promise})=>{ stream.pipeline( streamfrom, streamto, () => promise.then(()=>resolve({ 'statusCode': 200 })) ) }) }) } async function getS3Stream() { const streamto = new stream.PassThrough() const s3Client = new S3Client({ region: s3Region }) const upload = new Upload({ client: s3Client, params: { Bucket: bucketname, Key: "test/test.txt", Body: streamto } }) let promise = upload.done() return({streamto,promise}) }