satonabannana
satonabannana

Reputation: 13

Keep getting "Function returned undefined, expected Promise or value" when using a streaming API in Cloud Functions

I've looked all over Stack Overfow, and I've tried all the upvoted solutions, but still nothing works.

What this code does is take a link and download it into firebase storage, when it's succeeded, it updates the user value with the name of the video. I've tried putting a "return true" but all that happens is the code gets skipped and logs just say it finished with ok. Any thoughts on solving this?

exports.downloadVideo = functions.database.ref('/Requests/{pushId}/linkURL').onUpdate(event => {

var videoFileName = Math.random() + '.mp4'
var link = event.data.val();

var video = youtubedl(String(link))

video.on('info', function(info){

    console.log('Download started');

});

const remoteWriteStream = bucket.file(videoFileName).createWriteStream({
metadata: { contentType: 'video/mp4'}
});

video.pipe(remoteWriteStream)
.on('error', (err) => {
console.log(err)
})
.on('finish',() => {

admin.database().ref('Requests').child(event.data.ref.parent.key).update({'linkLocation' : videoFileName})
console.log("success")
        });
    });

Upvotes: 1

Views: 313

Answers (1)

Doug Stevenson
Doug Stevenson

Reputation: 317467

Since you're using a streaming/event style API to perform your work, you don't have the ability to simply return a promise from the final bit of work that needs to complete. In that case, you need to create your own promise, arrange for it to be resolved when the streaming is done, chain on that if necessary, and return the final promise. Here's a brief template for how that works:

return new Promise((resolve, reject) => {
    video.pipe(remoteWriteStream)
    .on('error', (err) => {
        console.log(err)
        reject() // reject the promise
    })
    .on('finish', () => {
        console.log("success")
        resolve() // resolve the promise
    });
})
.then(() => {
    // continue work after streaming is done
    return admin.database().ref('Requests').child(event.data.ref.parent.key)
        .update({'linkLocation' : videoFileName})
});

Note that you will have to apply this pattern to all of the times you use a streaming API and need to wait for the work to complete. It's incredibly important to think about what it takes to return a promise that's resolved only after all the async work is done in the function.

If you don't return a promise that resolves when all the work is complete, it will most certainly not behave the way you want.

Upvotes: 1

Related Questions