Search code examples
node.jsmultercloudinary

Cloudinary uploader.upload executed after next async command in file


I'm trying to upload file with Multer and cloudinary node.js api and then remove temp file from hard drive, however file gets deleted before upload finished. Then I commented unlink files uploaded correctly

Here is my controller

const createGame = async (req, res) => {
    const options = {
        use_filename: true,
        unique_filename: false,
        overwrite: true,
    };
    try {
        const data = req.body;
        const files = req.files;
        let posterPath = "";
        let videoPath = "";
        let distroPath = "";
        if (files?.poster?.length) {
            posterPath = files?.poster[0]?.path || "";
            try {
                const newPath = await uploader.upload(posterPath, options);
                // Bug - unlink happens before file uploaded
                await unlink(posterPath);
                posterPath = newPath as string;
            } catch (err) {
                // Upload failure - remove files from disk
                await unlink(posterPath);
                posterPath = "";
            }
        }
        if (files?.video?.length) {
            videoPath = files?.video[0]?.path || "";
            try {
                const newPath = await uploader.upload(videoPath, {
                    ...options,
                    resource_type: "video",
                });
                // Bug - unlink happens before file uploaded
                await unlink(videoPath);
                videoPath = newPath as string;
            } catch (err) {
                // Upload failure - remove files from disk
                await unlink(videoPath);
                videoPath = "";
            }
        }

        const currentPublisher = await publishersRepository.findOneBy({
            id: req.user.id,
        });

        if (!currentPublisher) {
            res.status = 301;
            return res.json({
                message:
                    "You must be authenticated as publisher in order to add a game",
            });
        }

        const newGameData = gamesRepository.create({
            ...data,
            poster: posterPath,
            video: videoPath,
            distro: distroPath,
            publisher: currentPublisher,
        });
        const newGame = await gamesRepository.save(newGameData);

        res.status(200);
        return res.json({ message: "Game added", data: newGame });
    } catch (err) {
        console.log("Error creating the game", err);

        res.status(400);
        return res.json({ message: "Error creating the game" });
    }
};

Solution

  • I'm assuming you're using just one multer instance.

    From what I looked at the docs of multer, the upload function is not a Promise. So the await function in front of uploader.upload method will not work.

    What you need is to promisify your upload function. Here's an example:

    const util = require('util');
    
    // your code ...
    try {
      const promisifiedUploadFunc = util.promisify(uploader.upload);
      const newPath = await promisifiedUploadFunc(posterPath, options);
      // Bug - unlink happens before file uploaded
      await unlink(posterPath);
      posterPath = newPath as string;
    } catch (e) {
      // continue code..
    }