博客

迁移到更大的工作区,又不让任何人等待

每个 Mythex 项目都有自己的工作区:一台小型云端计算机,智能体在上面编写代码,你的应用预览也在上面运行。我们已经把新工作区的内存从 1 GB 提升到了 2 GB,但旧的工作区仍然停留在 1 GB——在我们检查的那一天,大约有四分之一是这样。我们的第一个修复方案是在项目下次被打开时,把它迁移到更大的工作区。但在它上线的第一天,就让一个用户等了七分钟。于是我们为它设置了硬性时间上限,之后又干脆把迁移从打开项目这一操作中拿掉了。

为什么旧的工作区仍然很小

我们的沙盒提供商在工作区创建时就设定了它的大小,并在每次暂停和恢复时都保持这一设置。修改模板——也就是新工作区所基于的配方——只会影响修改之后创建的工作区,已经存在的工作区不会被调整大小。

这一点很关键。其中一个小工作区在预览启动时执行 git push 时内存耗尽,并且无响应了 11 分钟。一次发布因此失败。

第一次尝试:在唤醒时迁移项目

工作区在没有人使用时会暂停,在项目被打开时会被唤醒。唤醒的时候似乎是迁移项目的最佳时机,因为此时还没有人在里面工作。

迁移流程如下:

  1. 检查大小。 如果工作区小于 2 GB,就迁移。如果无法获知大小,则什么都不做。
  2. 不干扰正在进行的发布。 发布会读取工作区中的文件,因此如果有发布正在进行,就跳过迁移。
  3. 打包项目。 将项目中的所有内容打包成归档,包括它的 git 历史——也就是该项目拥有的每一个检查点——以及属于所有者的应用 .env 文件,但不包括已安装的依赖(node_modules),因为它们可以重新安装。
  4. 直接复制过去。 将归档从旧工作区以流的形式传输到一个全新的 2 GB 工作区,这样它就不必完整地放进我们自己服务器的内存中。
  5. 切换前先比对。 在两个工作区中分别统计文件数量,读取最新的检查点,并统计检查点的总数。只有三者全部一致,才会切换。
  6. 任何失败都保留旧工作区。 任何错误或任何不一致,都会丢弃新的工作区,并像以前一样在旧工作区中打开项目。

比对中有一个细节,比看起来更重要。这项检查以管理员账户运行,而 git 会拒绝读取属于其他用户的仓库。两边都没有输出任何内容——而“没有输出”与“没有输出”相匹配,于是检查通过了,实际上并没有比较任何历史记录。我们告诉 git 信任该目录,并添加了一个测试,确保这种情况不会再次出现。

第一天出了什么问题

在它上线的第一天,打包其中一个项目时触发了五分钟的命令超时——而这一切都发生在唤醒过程中。项目所有者等了七分钟,他的工作区才打开。而且由于迁移失败,项目仍然是小工作区,下一次打开时还会再次尝试,让他们再次等待。

在用户打开自己的项目时让他们等待的迁移,是一笔糟糕的交易。把迁移放在唤醒时执行,本意是让人们根本察觉不到它的存在。

第二次尝试:设定硬性时间预算

同一天,我们改动了四处:

  • 整个迁移只有一分钟。 每个步骤——检查大小、打包、创建新工作区、复制、解包、比对——共享同一个 60 秒的预算。预算耗尽时,项目就在旧工作区中打开。
  • 停止工作本身,而不仅仅是等待。 如果我们放弃等待,但归档仍在项目所有者即将使用的工作区内运行,那就毫无意义。现在,每个归档命令都会在预算结束前不久,于工作区内部被直接终止。如果新工作区在我们放弃之后才到达,它会被丢弃。
  • 不让用户等待清理。 删除临时归档文件的工作现在在后台完成。
  • 不在每次打开时都重试。 无法迁移的项目会被搁置 24 小时,因此一次失败最多只造成每天一次延迟,而不是每次打开都延迟一次。

第三次尝试:把迁移从唤醒中移除

这样一来,最坏的情况是一分钟。但一分钟仍然是一分钟,而且我们意识到,迁移根本不需要出现在任何人的必经之路上。

现在已经不会再创建 1 GB 的工作区了。因此,这不是一个持续进行的过程,而是一次性的任务,针对的是一份固定的工作区清单。在唤醒过程中执行迁移,意味着每一次缓慢的迁移都由真实的人来承担代价,而我们了解到某个工作区无法迁移的唯一方式,就是有人刚刚为此等了很久。

因此,我们把迁移从唤醒过程中彻底移除。打开项目的行为与之前完全一致。剩下的小工作区则改为作为一个受监督的批处理任务来处理:没有人在等待它,而无法迁移的工作区会出现在批处理的报告中,我们可以在那里进行查看,而不是出现在项目所有者面前。

我们的收获

  • 并非总能调整大小。 当平台在创建时就固定了大小,提高默认值只对新的东西有用。对于旧的东西,要另做打算。
  • “反正还没人在用”,并不代表没有人在等待。 在用户进入产品的途中所做的工作,是有人在旁边看着的。
  • 为用户路径中的任何操作设置预算,并在预算耗尽时停止工作。 在我们这边超时,而命令仍在别处继续运行,只是把问题转移了。
  • 一次性的迁移应当放在一次性的任务中。 把它藏在日常操作里,编写时更省事,运行时却代价更高。
  • 测试你的安全检查。 一个什么都没比较的比对,看起来与一个真正通过的比对完全一样。

如果你在 Mythex 上构建应用,无需做任何事:目标只是减少内存耗尽的工作区,同时让打开项目的速度保持不变。关于工作区如何暂停和唤醒,请参阅文档中的私有工作区。另一个关于内存耗尽的故事,请参阅隐藏在进度标签中的内存溢出崩溃。

Mythex · Pricing · 用 AI 构建任何东西 · 网站和应用模板 · Mythex 对比 · AI 应用构建术语表 · 免费的 AI 应用构建工具 · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 繁體中文(香港) 繁體中文(台灣)