skip to Main Content

I am building a logic to upload videos to cloudinary using node.js, next.js and multer package.
I have a mongodb document that I would like to store the video url and publicid of the video once cloudinary upload function completes.
This means that I would like to wait for the process to complete, sore it as part of my response before creating the document.

Unfortunately, I am unable to get this to work. The video upload takes time to complete. I would like to wait for the response to decide what to send back to the client.
Here is the cloudinary upload function:

export const largeFileUploader = async(props: {targetedFile: string})=>{
const {targetedFile} = props;

try {
   cloudinary.uploader.upload_large(targetedFile, 
    { resource_type: "video" , 
        chunk_size: 6000000, folder: 'folderName', upload_preset: 'presetName' }, 
    function(error, result) {
        console.log(error, 'error')
        if(error) throw 'Error encountered';
        
        return result
    });  
} catch (error) {
    console.log(error)
   throw 'file upload error';
};

};

I wrote another function that can be invoked in a route:

const imageUploadFunct = async(req: Request, res: Response, eventType: events)=>{   
    const files = req?.files as Express.Multer.File[];
    const imageUrl: string[] = [];
    const publicId: string[] = [];

  if(eventType === 'video_upload_event'){
    const uploadResponse = await largeFileUploader({targetedFile: file?.path}) as any;

    imageUrl.push(uploadResponse?.secure_url);
    publicId.push(uploadResponse?.public_id);

      if(file?.path){
         removeFile({filePath: file?.path});
       };
     return { imageUrl, publicId };
  }
};

Then in my controller, I have this:

export const httpUploadVideo = async (req: Request, res: Response)=>{

    try {
        const response = await imageUploaderFunc(req, res, 'video_upload_event');
        return res.status(200).json(response)
    } catch (error) {
        return res.status(500).json('Something went wrong, refresh your page or contact support');
    };

};

The cloudinary upload method takes time to complete the video upload before returning with response. Before then, my client already got response from me. Now, I need the cloudinary response to send to my client but before it can be ready, my code has already returned and sent response to client.
How do I make my code to wait until cloudinary returns a response before I send a response to the client?

I know there can be option for me to update the mongoose database background wise when cloudinary sends a a feedback by building something like an event hook. But I dont really wish to follow that path.

2

Answers


  1. The largeFileUploader function is async, but it doesn’t await anything. The asynchronous operation therein is using a callback rather than a Promise:

    cloudinary.uploader.upload_large(
      targetedFile,
      { resource_type: "video", chunk_size: 6000000, folder: 'folderName', upload_preset: 'presetName' }, 
      function(error, result) {
        console.log(error, 'error')
        if(error)
          throw 'Error encountered';
        return result
      }
    );
    

    If the service provides an awaitable API, it is recommended to use that instead. If they don’t, one option is to wrap this callback structure in a Promise and return that so consuming code can await it. For example:

    return new Promise(function(resolve, reject) {
      cloudinary.uploader.upload_large(
        targetedFile,
        { resource_type: "video", chunk_size: 6000000, folder: 'folderName', upload_preset: 'presetName' }, 
        function(error, result) {
          console.log(error, 'error')
          if(error)
            reject('Error encountered'); // <-- reject the Promise
          resolve(result); // <-- resolve the Promise
        }
      );
    });
    
    Login or Signup to reply.
  2. I just checked your code carefully and almost correct, but you made some mistakes in largeFileUploader function. cloudinary.upload.upload_large is async function so you should use await here to waits uploading results from cloudinary. But you didn’t used await and handled the result in callback of upload_large. In this case, the result will be returned once you already sent response to the client so it’s wrong. I provide updated code for it.

    export const largeFileUploader = async(props: {targetedFile: string})=> {
        const {targetedFile} = props;
    
        try {
            const result = await cloudinary.uploader.upload_large(targetedFile, {
                resource_type: 'video',
                chunk_size: 6000000,
                folder: 'folderName',
                upload_preset: 'presetName',
            });
    
            return result;
        } catch (err) {
            console.log(err)
            throw new Error('file upload error');
        }
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search