【问题标题】:Thumbnail Cloud Function fails with "Error: EBUSY: resource busy or locked, rmdir '/tmp/thumbs' at Error (native)"缩略图云功能失败并显示“错误:EBUSY:资源繁忙或锁定,rmdir '/tmp/thumbs' at Error (native)”
【发布时间】:2019-02-01 05:25:52
【问题描述】:

我的 Firebase 云函数失败并出现以下错误:

Error: EBUSY: resource busy or locked, rmdir '/tmp/thumbs' at Error (native)

通过我的功能,我为上传的图片创建缩略图并将它们保存到 Firebase 存储。我构建以下代码的方式一切正常(除了每个函数调用都失败)。但我担心由于 tmp 文件夹中的旧文件没有被删除,我的 tmp 文件夹会填满不必要的文件。

import * as functions from 'firebase-functions'

import {tmpdir} from 'os'
import {join, dirname} from 'path'

import * as sharp from 'sharp'
import * as fs from 'fs-extra'
import * as admin from "firebase-admin"

const storage = admin.storage()

/* Saves thumbnails for all userPics uploaded to Google Cloud Storage */
export const thumbnailCreator = functions.storage
    .object()
    .onFinalize(async object => {
        const bucket = storage.bucket(object.bucket)
        const filePath = object.name
        const fileName = filePath.split('/').pop()
        const bucketDir = dirname(filePath)
        const workingDir = join(tmpdir(), 'thumbs')

        /* Temporary: Creates a random number for the sourceFilePath
        * because currently bucket.file(filePath).download does not seem to overwrite
        * existing files and fs.rmdir(workingDir) does throw that error... */

        const randomNr = Math.random().toString(36).substring(2, 15) +
            Math.random().toString(36).substring(2, 15)

        const tmpFilePath = join(workingDir, `source_${randomNr}.png`)

        if (!object.contentType.includes('image')) {
            console.log('exiting function (no image)')
            return false
        }

        if (fileName.includes('thumb@')) {
            console.log('exiting function (already a thumbnail')
            return false
        }

        // 1. Ensure thumbnail dir exists
        await fs.ensureDir(workingDir)

        // 2. Download Source File
        await bucket.file(filePath).download({
            destination: tmpFilePath
        })

        // 3. Resize the images and define an array of upload promises
        const sizes = [64, 128, 256, 512]

        const uploadPromises = sizes.map(async size => {
            const thumbName = `thumb@${size}_${fileName}`
            const thumbPath = join(workingDir, thumbName)

            // Resize source image
            await sharp(tmpFilePath)
                .rotate()
                .resize(size, size)
                .toFile(thumbPath)

            // Upload to GCS
            const file = await bucket.upload(thumbPath, {
                destination: join(bucketDir, thumbName),
                predefinedAcl: 'publicRead'
            })

        })

        // 4. Run the upload operations
        await Promise.all(uploadPromises)

        // 5. Cleanup remove the tmp/thumbs from the filesystem
        return fs.rmdir(workingDir)
        // TODO: This fails every time -> also tried with fs.remove(workingDir), same issue.

    })

如您所见,我处理它的方式是为 source.png 的文件名提供 GUID,因为下次调用该函数时,它不会在执行 bucket.file(filePath).download() 时覆盖已下载的文件。

但我想清理我的 tmp 文件夹,但我不知道为什么该文件夹“忙或被锁定”。有没有办法在尝试删除之前解锁它?

更新 - 来自 DOUG 的解决方案

正如道格在下面回答的那样,在删除文件夹之前删除所有文件是可行的。所以我最终这样做了:

// 5. Cleanup remove the tmp/thumbs from the filesystem
await fs.emptyDir(workingDir)
await fs.remove(workingDir)

【问题讨论】:

    标签: javascript firebase google-cloud-functions firebase-storage


    【解决方案1】:

    我不知道这是否会导致 EBUSY,但是 rmdir(节点的版本和同名的 unix 命令行)要求目录在调用之前为空。您将文件留在了那里,这可能会导致 rmdir 失败。尝试单独删除每个生成的文件,然后删除目录。

    【讨论】:

    • 谢谢道格,这有帮助!我忘了在上面提到我已经用 fs-extra 的fs.remove() 尝试过它应该删除其中包含文件的文件夹,但神秘地发生了同样的错误。现在首先使用fs.emptyDir(workingDir) 删除文件,然后使用fs.remove(workingDir) 删除目录才能正常工作。我知道我可以相信你的披萨 ;-)
    猜你喜欢
    • 2019-08-08
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2019-01-03
    • 2021-08-21
    相关资源
    最近更新 更多