0

I'm trying to collect all the documents from a specific file and transform them into a Sendgrid attachment object with a content and filename property.

Step 1 and 2 are working. After step 2 I have an array of objects with some document data like the file name, type, storage URL etc.

In step 3 I want to fetch the actual file based on the storage URL and create a Sendgrid attachment object. It requires content and filename as properties.

However, with my current code, the attachments array stays empty when I'm logging the variable.

My code:

export const onStatusChanged = functions.database.ref(`files/{fileID}/general/status`).onUpdate(async (change, context) => {
    const prevStatus = change.before.val();
    const currentStatus = change.after.val();

    if (prevStatus === currentStatus) return null;

    if (currentStatus === 'email') {
        // 1. Get file data
        const snapshot = await change.after.ref.parent.parent.once('value');
        const file = snapshot.val();

        // 2. Get documents
        const documents = getDocuments(file.documents);
        console.log(documents);

        // 3. Create attachments
        const attachments = [];

        documents.forEach(document => {
            axios.get(document.url, { responseType: 'arraybuffer' }).then(image => {
                attachments.push({ content: Buffer.from(image.data).toString('base64'), filename: document.name });
            }).catch(error => {
                console.log(error)
            })
        });

        console.log(attachments) // []

        // 4. Create email object

        // 5. Send email
    }

    return null;
})

I thought by using a promise my code is synchronous?

EDIT: first I had this code

    // 3. Create attachments
    const attachments = documents.map(document => {
        const image = await axios.get(document.url, { responseType: 'arraybuffer' });
        return attachments.push({ content: Buffer.from(image.data).toString('base64'), filename: document.name });
    })

    console.log(attachments) // [ Promise { <pending> } ]
2
  • "I thought by using a promise my code is synchronous?" -> as you discovered, that's not the case. There are different ways to sequentialize async code -- we used to do async.waterfall and maybe this is still done. You might be thinking about using await. This new keyword makes async code look synchronous, though it is still definitely async. Have you tried await in your forEach? Commented Mar 7, 2019 at 3:30
  • @RayToal: First I did use await with a map() function. Added this code Commented Mar 7, 2019 at 3:41

2 Answers 2

1

I think you misunderstand the use of promises specifically with Cloud Functions. With Cloud Functions background triggers, you are obliged to return a promise that resolves when all the async work is fully complete, else the work will be shut down. Right now you are returning null, which isn't correct.

Also, attachements doesn't seem to be accumulating promises. It's accumulating other objects that are not useful for async programming.

Read more in the documentation: https://firebase.google.com/docs/functions/terminate-functions

Sign up to request clarification or add additional context in comments.

2 Comments

I will check the documentation and come back afterward. Thanks for the url.
Changed the code to async/await and wrapped the loop in Promise.all(). At the end of the if-condition (step 5) I will return a promise when sending the actual email.
0

Changed the code back to async/await and added Promise.all(). It's working like I want now.

The code:

    const attachments = await Promise.all(documents.map(async document => {
        const image = await axios.get(document.url, { responseType: 'arraybuffer' });
        return { content: Buffer.from(image.data).toString('base64'), filename: document.name };
    }));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.