0

我正在编写一个 Discord 机器人并将其部署到 heroku。我有一个机器人功能,它将接收视频文件并将其从任何格式转换为 .mp4,然后机器人回复嵌入的文件。

在本地,一切运行正常,而且我知道 Heroku 使用临时文件系统,但考虑到我并不真正关心持久化这些文件,我认为在磁盘上创建它们、回复然后删除它们就可以了。

但是,每当我在部署的机器人上运行命令时,我都会收到此错误错误:ENOENT:没有这样的文件或目录,stat '/app/dest/videostoconvert/851730039589306388.mp4'

const getAndConvertVideoFile = async (
    message: Discord.Message,
    url: string,
    inputPath: string,
    outputPath: string
) => {
    try {
        if (!fs.existsSync(path.join(__dirname, "../../", "videostoconvert"))) {
            const mkDirPromise = util.promisify(fs.mkdir);
            await mkDirPromise(path.join(__dirname, "../../", "videostoconvert"));
        }
    } catch (error) {
        console.log("ERROR CREATING DIRECTORY");
        console.error(error);
    }

    const response = await axios({
        method: "get",
        url: url,
        responseType: "stream"
    });

    console.log("INPUT PATH", inputPath);
    // INPUT PATH /app/dest/videostoconvert/851730039589306388.m4v
    console.log("OUTPUT PATH", outputPath);
    // OUTPUT PATH /app/dest/videostoconvert/851730039589306388.mp4
    try {
        const diskWriteStream = fs.createWriteStream(inputPath);
        response.data.pipe(diskWriteStream);

        diskWriteStream.on("error", (error) => {
            console.log("DISK WRITE ERROR");
            console.error(error);
        });

        diskWriteStream.on("finish", async function () {
            hbjs.spawn({ input: inputPath, output: outputPath })
                .on("error", (error: any) => {
                    console.error("THERE WAS AN ERROR", error);
                    console.log("There was an error", error);
                })
                .on("progress", (progress: any) => {
                    console.log("Percent complete: %s, ETA: %s", progress.percentComplete, progress.eta);
                })
                .on("complete", async () => {
                    console.log("COMPLETE");
                    // seems to be where it fails, heroku logs "COMPLETE" and then the error
                    const attachment = new Discord.MessageAttachment(outputPath);
                    

                    await message.reply(attachment);
                });
        });
    } catch (error) {
        console.log("ERROR GETTING AND CONVERTING FILE");
        console.error(error);
    }
};

我在代码中添加了一些可能有帮助的注释。在我看来,这意味着该目录不存在,但如果该目录在代码的前面不存在,我将创建该目录,所以我不确定是什么导致了问题。此外,根据 Heroku 控制台输出,故障点似乎发生在 hbjs.spawn.on("complete", ...) 行,因此该目录似乎是为了在下载文件后写入文件而创建的。

我会说,我不反对使用 S3 来托管文件而不是直接写入 heroku 磁盘,但我不确定在这种情况下如何转换它们,sine hbjs 似乎期待磁盘写出转换文件的路径。

4

1 回答 1

0

我怀疑这与内部事实有关,handbrake-js 产生了一个单独的进程(HandbrakeCLI二进制文件)来产生输出(编码的视频文件)。然后,Node.js 进程需要保持活动状态足够的滴答声以允许子进程完成。

也许 Heroku 在给 fs 和/或 handbrake-js 时间完成之前终止了 Node.js 进程。

我个人会尝试从使用 fs 和 handbrake-js 的基于事件的接口(即监听事件)切换到使用async方法和Promise-yielding 接口。请参阅fs/promiseshandbrake-js 的 .run() 方法

于 2021-06-20T10:13:36.397 回答