数据保护背景下,安全团队引入了哪些新技术进行防控升级?点击学习案例 了解详情
写点什么

我在产品上线前不小心删除了 7 TB 的视频

  • 2022 年 5 月 16 日
  • 本文字数:4113 字

    阅读完需:约 13 分钟

我在产品上线前不小心删除了7 TB的视频

今天我们想分享的是一位初级开发者对于自身犯的某个错误的记录。这个帖子在日前在 Hacker News 之所以引起很多人的讨论和共鸣,或许是因为许多经验丰富的工程师都是这么走过来的。


虽然这是一个“新手贴”,但它也是不错棒的帖子。犯错不可怕,最重要的是,犯错后能吸取经验教训,让自己会变得更强大。这位开发者把它写下来巩固自己学习过程中的理解,这对任何有类似经验的初级开发人员来说都是有积极意义的。人人都会犯错,关键是下一步怎么做。以下是帖子内容,我们将其翻译出来,希望能为读者带来参考价值:

前言

先跟大家打个招呼,我是个刚工作还不到一年的初级开发者,所以很多在各位看来不言而喻的道理我自己还没摸索清楚。本文权当记录成长过程中的点滴,请大家轻拍。


在很多高手们看来,这个故事简直不可理喻……没错,里头有太多坏习惯、太多低级错误,在硅谷巨头看来完全不可想象。但这就是世界各地小型 IT 企业的真实生存状态,而且还在继续困扰着无数像我这样的从业者。


我目前是在意大利一家小开发公司(一共 10 个人)上班,主要是为当地企业开发管理各种网站和工具。另外,我们还跟意大利、英国和南非最大的几家健身企业签订了大额合同。既然说是最大的健身企业,那他们应该知道自己想要什么喽?错,他们完全不知道……当然,我不打算把锅甩给他们,毕竟这里的甲方和乙方都是一屁股烂账、谁也别说谁。总之,让咱们客观回顾事件原委。

从项目说起

受保密协议所限,这里我没法透露太多。简而言之,我们目前开发的项目需要使用大量视频,这些视频素材托管在 Vimeo 之上。公司当前用的是 VimeoOTT,也就是负责内容交付的前端平台,但上头打算逐步迁移至 Vimeo Enterprise。VimeoOTT 上需要迁移的视频大概有 500 段,但 Vimeo 并不提供简单易行的迁移方法。去年 10 月左右,我曾经写信给对方的支持团队,询问他们能不能帮助迁移,回复中说他们“会调查一下”。然后就没有然后了。


所以说,我们得重新上传这些视频素材。我提议构建一个自定义 API 脚本,从 OTT 那边下载视频、再把素材上传至 Enterprise(和我们的产品)。但管理层拒绝了这套方案,而是决定花钱请人来手动完成。接下来的一个月中,有人上传了来自 OTT 的 500 段视频外加 400 段新视频,于是我们一下子就用光了 Enterprise 提供的全部 11 TB 存储容量中的 9 TB,好在一切进展顺利(虽然效率不高)。时间很快来到今年 4 月。

出问题了

突然之间,Vimeo 那边似乎开了窍,想起我们之前提出的申请。于是在并未告知我司的情况下,他们决定把 OTT 上的所有视频都转储到 Enterprise 新平台上。但为什么不打个招呼呢?可能 Vimeo 根本就不关心吧。


  1. 他们重复上传了我们这边已经传过的视频。

  2. 现在视频素材的总大小在 15 TB 左右,超出上限 4 TB。就是说除非我们删除一部分内容,否则根本没法继续上传视频。我们询问 Vimeo 能否恢复更改,但得到的却是否定的答复。最要命的是,再有一个礼拜左右产品就该上线了。


唯一的选择就只能是手动删除多出来的视频了,这活归我来干。很遗憾,我犯了个巨大的错误。

“解决方案”

(介绍一下背景,之前 7 个月里我一直在使用 React,这也成了引爆问题的直接导火索)


幸运的是,我们在数据库里为每段视频都分配了一个“VimeoId”,所以我脑袋里蹦出的第一个解决方案就是:


for each video in vimeo:    if video not in our_vimeo_ids:    delete("api.vimeo.com/videos/{video}"
复制代码


这两条请求都是分页的(只是具体方式略有不同),所以我编写的实际代码是:


page = 0url = f"https://api.ourservice.com/media?page={page}&step=100"our_ids = []for i in range(10):    page = i    res = requests.get(url)    videos = res.json()['list']    ids = [video['vimeoId'] for video in videos]    our_ids += ids
next = '/me?page=1'vimeo_ids = []while next is not None: res = requests.get(f'https://api.vimeo.com/videos{next}') res = res.json() videos = res['data'] ids = [video['id'] for video in videos] vimeo_ids += ids next = res['pagination']['next']
for id in vimeo_ids: if id not in our_ids: requests.delete(f'https://api.vimeo.com/videos/{id}')
复制代码


大家肯定一看就知道错在哪了,现在我也看得出来。但当时我检查了好几遍,觉得它没有任何问题。这里剧透一下答案:


url = f"https://api.ourservice.com/media?page{page}&step=100our_ids = []for i in range(10):    page = i    res = requests.get(url)
复制代码


我当时已经习惯了 React,所以天然认定 url 会在页面变量更改后立即刷新,但事实并非如此。所以在使用这个脚本之后,所有不存在于我们数据库第一页里的视频都会被从 Vimeo 中删除。


这里还有另一个问题:我测试了代码,并使用了以上示例中的这个错误循环。


page = 0url = f"https://api.ourservice.com/media?page{page}&step=100our_ids = []for i in range(10):    page = i    res = requests.get(url)    videos = res.json()['list']    ids = [video['vimeoId'] for video in videos]    for id in ids:    res = requests.get(f'https://api.vimeo.com/videos/{id}')        if res.status_code != 200:        print(f"There was something wrong. You have deleted a wrong video -> {id}")
复制代码


我还做了几次手动测试,但测试范围就只有数据库上的第一页。哎,这本该很容易避免的一系列错误。

善后工作

好消息是,Google Drive 文件夹里还有一份视频备份,而且相关信息也好好保存在数据库内。坏消息是,这时候时间已经来到星期五,而我们最晚也得在星期二早上就把视频还原回去。当时公司的网络带宽大概是每秒 30 MB,上传数据总量在 8 TB 左右。不现实……我们得想点别的办法。


我想到的第一个解决方案就是用 Google Drive API。我们这边有全部上传到数据库的视频文件名,所以我很快写下以下代码:


page = 0file_names = get_our_filenames(page) # This time without the mistake in the for loopfor name in file_names:    download_and_save_from_drive(name)    upload_to_vimeo(name)
复制代码


这意味着我可以用不同页面多次运行脚本,从而在不同网络上“并行化”整个过程。(我也想过换个高速网络环境,但一是没有比较快捷的提速途径、二是出站流量成本过高。)效果还是不理想,毕竟就算是饱和传输也得占满整整 4 天,再出一丁点问题就要超时。于是我又想到了一个办法:


另一个解决方案


能不能直接把视频从 Google Drive 上传到 Vimeo?我检查了一下上传页面,并发现确实可以这么操作。只是还有个小问题:它只支持手动操作,无法使用 API 自动优化,但优势是上传几乎可以即时完成。也许还有更好的办法,但我当时真的想不到了,所以我满心欢喜地启动了 Playwright。


Playwright 是一款自动 E2E 工具,可用于模拟用户交互。具体来讲,它可以按我们编程的指引点击网站上的不同位置。有它在,不就把人给解放出来了?


下面来看代码:(我刚开始用 Playwright、而且时间紧迫,所以写得确实粗糙,请大家原谅)


test('Videos', async ({ page }) => {  // 登录进vimeo  await page.goto('https://vimeo.com/upload/videos');  await page.fill(    'input[name="email"]',    'xxx'  );  await page.fill('input[name="password"]', 'xxx');  await page.click('input[type=submit]');
// 点击Drive按钮,然后登录进 Google Drive // 我们需要将其作为iframe来管理 const [popup] = await Promise.all([ page.waitForEvent('popup'), page.click('text=Drive'), ]); await popup.fill('input[type="email"]', 'xxx'); await popup.click('button:has-text("Next")'); await popup.fill('input[type="password"]', 'xxx'); await popup.click('button:has-text("Next")'); await timeout(5000);
// 对于我们上传前就已经获得的全部文件名 for (let i = 0; i < videos.length; i++) { if (i > 0) { page.click('text=Drive'); await timeout(5000); } let found = false; while(!found) { for (let frame of page.frames()) { const searchbox = await frame.$('input[aria-label="Search terms"]'); const button = await frame.$('div[data-tooltip="Search"]'); if (searchbox) { await temp.fill(videos[i]); await button.click(); } } } await timeout(5000);
// 每当搜索时,Google都会重新生成iframe,所以我们就得重新搜索 for (let frame of page.frames()) { const temp = await frame.$('table[role="listbox"] div[tabindex="0"]'); if (temp) { const select = await frame.$('div[id="picker:ap:2"]'); await select.click(); } } await page.goto('https://vimeo.com/upload/videos'); }});
复制代码


这段代码确实不怎么样(特别是其中用超时来解决 Playwright 中.click()的部分),但它还是发挥了符合预期的效果,只有一个意外:我没能让它正确点击查找到的视频,而只是点到了“Select”按钮上。直到现在,我也不知道这个问题该怎么解决。所以就算是用上这段代码,我也得每 10 秒就手动单击一次来选择视频,这样才能让程序持续运行。我坐在屏幕前点了 10 分钟,然后开始怀疑自己这是在搞什么鬼……


我下载了一个自动点击器(xclicker),并把它设置成每 5 秒点击一次。成功!每段视频大概耗时 13 秒,一共 1000 段视频,用了 4 个小时所有视频就都上传完成了。现在只剩最后一步:


它们都有了新的“vimeoIds”,所以我得回到公司这边的数据库,用正确的 Id 值更新所有视频。但这次要简单得多,用跟之前类似的 Python 脚本就能轻松完成。


最后,所有视频上传完成,产品终于能顺利上线了。

总结

这事让我学到了什么?首先就是在执行破坏性操作之前,先充分进行测试。也希望 Vimeo 和外包商也能从中吸取教训吧,虽然我怀疑他们根本不在乎。(肯定不在乎,直到现在这种上传方式还是只支持手动,想想这是为什么!)


原文链接:


https://blog.thevinter.com/posts/vimeo

2022 年 5 月 16 日 18:463296
用户头像
罗燕珊 InfoQ中文站编辑

发布了 265 篇内容, 共 108.3 次阅读, 收获喜欢 505 次。

关注

评论 1 条评论

发布
用户头像
Playwright是否类似于国内的“按键精灵”呢?
2022 年 05 月 19 日 13:28
回复
没有更多了
发现更多内容

filecoin全网有效算力突破10EiB?Filecoin挖矿现在还有机会入场吗?

区块链 分布式存储 IPFS filecoin挖矿 filecoin矿机

Vector向量计算技术与SIMD技术的对比

Roy夹馍

cpu IoT 芯片 risc-v

数字人民币与智能合约

CECBC

补课班用什么管理系统?染书CRMA,赋能教培机构信息化

亿欧之

托管班用什么管理系统?染书CRMA,自带营销工具提升续班率

亿欧之

RVB2601开发板用户指南

Roy夹馍

IoT risc-v 嵌入式开发

Paxos理论介绍(3): Master选举

OpenIM

Paxos理论介绍(2): Multi-Paxos与Leader

OpenIM

图像之场景分类 实验研究

毛显新

人工智能 神经网络 深度学习 图像识别 PyTorch

极光笔记丨Locust性能测试工具的使用

极光JIGUANG

软件测试 测试工具

在线考试系统有哪些?快考题|企考云,高频互动的培训功能免费用

亿欧之

ipfs最新官网通知?ipfs是一场技术革命?

区块链 分布式存储 IPFS Filecoin ipfs挖矿

天津赛誉食品有限公司与小王庄黄金梨携手 助推文旅产业化联盟销售

InfoQ 天津

一文看懂RISC-V代码密度

Roy夹馍

物联网 risc-v 嵌入式开发

ipfs挖矿是什么意思?ipfs挖矿靠谱吗?

ipfs挖矿靠谱吗 ipfs挖矿是什么意思

从芯片到云全链路高效设计 一文了解YoC基础软件平台

Roy夹馍

物联网 risc-v 嵌入式开发

中断实时性及处理技术简介

Roy夹馍

物联网 risc-v 嵌入式开发

玄铁VirtualZone:基于RISC-V架构的安全扩展

Roy夹馍

cpu 物联网 嵌入式开发

RVB2601开发板快速上手教程

Roy夹馍

MCU risc-v 嵌入式开发

澳鹏Appen收购Quadrant:移动定位数据业务进一步增强

澳鹏Appen

人工智能 大数据 企业 收购

平头哥剑池CDK 更新重磅来袭!三大亮点速看!

Roy夹馍

物联网 risc-v 嵌入式开发 软件模拟

财经大课:看懂价格信号

石云升

财经思维 9月日更

fil矿机8T多少钱?fil矿机多少钱一台?

FIL矿机多少钱一台 fil矿机多少钱

辅导班用什么管理系统?染书CRMA,课时班级信息自动罗列

亿欧之

如何创建网上试卷?快考题|企考云,专项练习降低人工阅卷失误率

亿欧之

如何建立微信考试?快考题|企考云,轻松拥有HR在线测评系统

亿欧之

解析金融服务如何在区块链中建立信任?

CECBC

EMQ X VS RabbitMQ:两大消息服务器 MQTT 性能对比全解(上)

EMQ映云科技

RabbitMQ 物联网 IoT mqtt emq

ipfs矿机工作原理是什么?ipfs矿机多少钱一台?

IPFS矿机多少钱一台 ipfs矿机工作原理是什么

平头哥玄铁CPU调试系统介绍

Roy夹馍

cpu risc-v 嵌入式开发 调试系统

人工智能是下一个“新生代农民工”吗?

澳鹏Appen

人工智能 大数据 AI 数据标注 训练数据

4k/8k超高清时代,如何利用媒体处理技术加速数字化升级

4k/8k超高清时代,如何利用媒体处理技术加速数字化升级

我在产品上线前不小心删除了7 TB的视频_文化 & 方法_thevinter_InfoQ精选文章