【问题标题】:Is there a way to schedule a deletion of a file on Firebase Storage?有没有办法安排删除 Firebase 存储上的文件?
【发布时间】:2021-08-15 17:05:33
【问题描述】:

我正在尝试构建一个允许用户上传和下载一些文件的 ReactJS 应用程序。我的应用中已经具备 Firebase 存储上传和下载功能。问题是我想安排一个任务,例如每次用户上传他的文件时,该任务将在 10 分钟内删除一个文件。

有什么建议吗?

【问题讨论】:

    标签: reactjs firebase google-cloud-storage firebase-storage


    【解决方案1】:

    Firebase 没有为此内置任何内容,但 Cloud Storage(底层存储机制)具有称为 object lifecycle management 的东西,其中:

    您可以将生命周期管理配置分配给存储桶。该配置包含一组适用于存储桶中当前和未来对象的规则。当对象满足其中一个规则的条件时,云存储会自动对该对象执行指定的操作。

    如果删除规则真的像你说的那样恒定,那就是我要看的地方。

    如果规则更复杂,我通常会从 Cloud Functions 开始,因为我可以写 code that run periodically 来进行清理。

    【讨论】:

      【解决方案2】:

      如果您正在为此寻找可靠的服务器端解决方案,您可以使用Scheduled Cloud Function

      这是一个基于节点的云函数的实现:

      import * as admin from "firebase-admin";
      import * as functions from "firebase-functions";
      
      admin.initializeApp();
      
      /**
       * Scheduled Cloud Function that deletes files older than 10 minutes,
       * checking every 5 minutes.
       *
       * Files must be prefixed with "tmpUserUploads" to be checked by this
       * function. If a file has a temporary or event-based hold on it, it
       * will be skipped over by this function.
       *
       * @author samthecodingman [MIT License]
       * @see https://stackoverflow.com/a/67724030/3068190
       *
       * @example
       * "tmpUserUploads/someFile.png" // -> checked
       * "tmpUserUploads/users/someUserId/someFile.png" // -> checked
       * "profilePictures/someUserId/profile@1x.png" // -> not checked
       */
      export cleanupTemporaryFiles =
      functions.pubsub.schedule('every 5 minutes').onRun(async (context) => {
        // variables for tracking statistics
        let processedCount = 0, disposedCount = 0, skippedCount = 0, erroredCount = 0, totalCount = 0;
        const errorCountsByCode = {};
        
        try {
          const bucket = admin.storage().bucket();
      
          // Query for all files starting with "tmpUserUploads"
          const [filesArray] = await bucket.getFiles({
            prefix: "tmpUserUploads"
          });
          
          totalCount = filesArray.length;
      
          // variables with our settings to be reused below
          const TIMESTAMP_TEN_MINUTES_AGO = Date.now() - 600000;
          const DELETE_OPTIONS = { ignoreNotFound: true };
      
          // If this number is regularly large, consider shortening the interval above
          console.log("Found ${totalCount} files that need to be checked.");
      
          // Process purge of each file as applicable keeping track of the results
          const deleteOldFileResults = await Promise.all(
            filesArray.map(async (file) => {
              let metadata;
              try {
                // get the metadata for this file object
                [metadata] = await file.getMetadata();
      
                // pull out the bits we need
                const { temporaryHold, eventBasedHold, timeCreated } = metadata;
      
                // held files should not be deleted (will throw an error if you try)
                const activeHold = temporaryHold || eventBasedHold;
      
                // dispose when not held and older than 10 minutes
                const dispose = !activeHold && timeCreated < TIMESTAMP_TEN_MINUTES_AGO;
      
                if (dispose) {
                  await file.delete(DELETE_OPTIONS);
                  disposedCount++;
                } else if (activeHold) {
                  skippedCount++;
                }
                
                processedCount++;
      
                return { file, metadata, disposed: dispose, skipped: activeHold };
              } catch (error) {
                // trap the error so other files still attempt to be deleted
      
                erroredCount++;
                processedCount++;
      
                const code = deleteResult.error.code || "unknown";
                const errorCountForCode = (errorsByCode[code] || 0) + 1;
      
                // Consider crashing function if same error code is encountered many times
                // if (errorCountForCode > 10) {
                //   throw new Error(`Error code "${code}" has been encountered more than 10 times`);
                // }
      
                errorCountsByCode[code] = errorCountForCode;
      
                return { file, metadata, disposed: false, skipped: true, error };
              }
            })
          );
      
          // Assemble an informative log message
      
          const skippedLogMessage = skippedCount === 0
            ? "No files had active holds"
            : `${skippedCount} of these were skipped due to active holds`;
          const errorLogMessage = erroredCount === 0
            ? "no errors were encountered"
            : `${erroredCount} were skipped due to errors (Error code breakdown: ${JSON.stringify(errorCountsByCode)})`;
      
          console.log(`${disposedCount}/${totalCount} temporary files were purged. ${skippedLogMessage} and ${errorLogMessage}.`);
        } catch (error) {
          const stats = JSON.stringify({
            disposed: disposedCount,
            skipped: skippedCount,
            errored: erroredCount,
            errorCodeCounts: errorCountsByCode
          });
          
          console.error(`Critical failure: ${error.message}. Encounted after processing ${processedCount}/${totalCount} files: ${stats}`);
        }
      })
      

      【讨论】:

        猜你喜欢
        • 2023-02-25
        • 2021-12-18
        • 2017-05-16
        • 2020-10-01
        • 1970-01-01
        • 2020-08-11
        • 2018-09-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多