【问题标题】:Making sure I do not overwrite a file on Cloud Storage by accident确保我不会意外覆盖 Cloud Storage 上的文件
【发布时间】:2022-11-14 02:13:36
【问题描述】:

(Node.js API)

我正在尝试执行以下操作:

  1. 生成文件路径,如/uploads/${uuid.v4()}.extension
  2. 写入文件。

    这是代码:

        const path = `/uploads/${uuidv4()}.${extname(fileName)}`;
        const file = bucket.file(path);
        await new Promise((resolve, reject) =>
            data
                .pipe(file.createWriteStream({ contentType }))
                .once('error', reject)
                .once('finish', resolve),
        );
    

    它工作正常。但是让我烦恼的是,生成相同 UUID 的可能性微乎其微。这不是一个实际问题。

    如何将数据上传到 Cloud Storage,但如果发生冲突会出现错误?我可以事先检查文件是否存在,但技术上仍然存在竞争条件......

【问题讨论】:

  • 我想知道对象版本控制是否有一些可能性?请参阅... cloud.google.com/storage/docs/object-versioning 如果我正确地理解了这一点,那么如果创建了两个相互重叠的 GCS 对象并且正在运行对象版本控制,那么我们可以(理论上)通过向 GCS 询问是否发生了碰撞文件的详细信息,包括其版本。我在想象两个同名的 GCS 文件被同时创建......当我们稍后查询“文件”时,我们会发现它有两个版本。
  • @Kolban 那么每个上传客户端如何调和他们可能已经上传了 n>1 版本的对象的事实,并弄清楚如何从中回退?不是微不足道的。如果没有事务性 API,每个人都只是盲目地上传新版本。

标签: google-cloud-platform google-cloud-storage


【解决方案1】:

碰撞的可能性不仅很小:对于大尺寸的 UUID 来说,它是天文数字的低。努力解决这种碰撞问题可能不值得。

也就是说,如果您仍然想这样做,您将无法单独使用 Cloud Storage API 来完成,因为没有可与之交互的事务性原子 API。如果你想要一个没有冲突的“硬”保证,你将需要与一个完全不同的云服务交互,它允许你有效地“锁定”一些唯一的字符串(例如文件路径)作为所有其他进程的标志检查以确保它们不会发生碰撞。由于您在 Google Cloud 中工作,您可能需要考虑使用具有原子事务操作的数据库(如任何 SQL 数据库或 Firestore)来“保留”路径,以便只有一个进程可以使用它(假设他们都正确地遵守了这一点)预订和合作)。

【讨论】:

  • 我知道它真的很低。我正在做一个玩具项目,这对我来说只是一种心理锻炼。我知道我可以使用 Firebase 文档的 ID 来存储一些扩展元数据。我很好奇是否可以在没有其他系统的情况下做到这一点......
  • 因此,从 Firestore 或实时数据库随机生成的 ID 本质上也是在客户端应用程序(而不是服务器)上生成的 UUID。它也可能有冲突,also astronomically low
  • 我认为它就像关系数据库中的 rowId - 保证唯一。无论如何,我暂时忽略这个问题。我在上传文件夹中添加了日期,因此现在风险更低。
【解决方案2】:

这不正是先决条件的目的吗?

从文档中复制:https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-nodejs

const options = {
    destination: destFileName,
    // Optional:
    // Set a generation-match precondition to avoid potential race conditions
    // and data corruptions. The request to upload is aborted if the object's
    // generation number does not match your precondition. For a destination
    // object that does not yet exist, set the ifGenerationMatch precondition to 0
    // If the destination object already exists in your bucket, set instead a
    // generation-match precondition using its generation number.
    preconditionOpts: {ifGenerationMatch: generationMatchPrecondition},
  };

  await storage.bucket(bucketName).upload(filePath, options);
  console.log(`${filePath} uploaded to ${bucketName}`);

【讨论】:

    猜你喜欢
    • 2020-01-21
    • 2012-07-20
    • 2012-03-25
    • 2019-11-15
    • 2022-10-23
    • 2019-11-26
    • 1970-01-01
    • 2012-03-08
    • 2018-02-19
    相关资源
    最近更新 更多