开发函数计算的正确姿势 —— 排查超时问题

本文涉及的产品
Serverless 应用引擎 SAE,800核*时 1600GiB*时
函数计算FC,每月15万CU 3个月
简介: 写不尽的 code,查不完的 bug 通常我们写 bug,哦,不对,写代码时总不会一帆风顺,往往各种 bug 充斥其中,即使测试有较高的代码覆盖率往往也会有漏网之鱼。能写出一些比较隐蔽或者看起来像 feature 的 bug,并且经过了测试、code review 等层层的考验,最终 merge 到主干,这也算的上是一种本事。

写不尽的 code,查不完的 bug

通常我们写 bug,哦,不对,写代码时总不会一帆风顺,往往各种 bug 充斥其中,即使测试有较高的代码覆盖率往往也会有漏网之鱼。能写出一些比较隐蔽或者看起来像 feature 的 bug,并且经过了测试、code review 等层层的考验,最终 merge 到主干,这也算的上是一种本事。

这次,我们讨论的场景是,当你制造的 bug 被别人发现或者不小心把自己坑了,而不得不去 fix,且你自己也忘了这个 bug 是怎么写的了,在这种情况下,如何排查问题?

一气呵成,bug 侧漏

var request = require('request');

exports.handler = function(event, context, callback) {
    console.log("event: " + event);
    console.log('context: ', JSON.stringify(context));

    const options = {
        url: 'https://saweather.market.alicloudapi.com/spot-to-weather?area=%E6%B3%B0%E5%B1%B1&need3HourForcast=0&needAlarm=0&needHourData=0&needIndex=0&needMoreDay=0',

        headers: {
            Authorization: 'APPCODE 5d9129e294fc4f518793ae9f9a15dbff'
        }
    }

    request(options, function (error, response, body) {
        if (error || response.statusCode != 200) {
            console.log("error " + error);
            return 
        } 

        console.log(body.day_weether);
    });
};

很简单的一个 nodejs 函数,刚刚接触函数计算往往会意气风发的一口气抒写出这样一段代码,通常是为了简单测试一下函数的使用流程。但是发布到上去后,却出现了调用超时的问题。

大胆猜测,小心求证

首先,在无从下手的情况下,你大胆猜测如下:

  1. 函数入口写错了
  2. 代码中的逻辑有问题
  3. 函数计算服务有问题

为了排除其中的 3 选项,首先通过 fun local,在本地运行测试:

fun local invoke nodejs_timeout

得到结果:

可以看到,程序也被卡在这里了。由此,可以排除掉 3 的可能性。

接着,可以通过加一些日志,或者单步调试来进一步缩小排查的范围,这里选用单步调试,因为这种方法往往更简单。

首先,利用 VSCode 在侧边栏下一个断点:

然后使用以下命令将函数以调试的方式运行起来(调试基本用法 参考,这里不再过多阐述):

fun local invoke -d 3000 nodejs_timeout

然后单击 VSCode 的开始调试按钮进行调试:

可以看到,函数被正确的调用了,且进入到了入口函数。到此为止,可以排除掉 1 的可能性。

接下来,就要确认 2 可能性中存在的问题。

在 request 处的代码设置断点,continue 到里面,然后在 Local 可以看到运行到此处时的变量的值。

可以看到,http 请求返回的 resposne 的 statusCode 为 200,符合预期。body 也是有数据的,这个也符合预期。

body.weakday 放到 watch 里面执行一下,看下结果。

这个就不是预期中的值了。

仔细看下 body 这个对象,发现其显示格式不对,通过 typeof 将 body 的类型打印出来:

这货竟然是个 string

刚想破口大骂,但一想这代码是自己写的,赶紧闭嘴。

那就转成 json 吧。

但转完后,发现事情更不对了,day_weether 并不直接在 body 下,而是隐藏的很深。

而且名字不叫 day_weether,这里有个拼写错误。正确的写法应该是:

JSON.parse(body).showapi_res_body.f1.day_weather

What the.... 脏话都到嘴边了,但一想代码自己写的,总不能骂自己吧,赶紧修吧。

把正确的表达式贴到 Watch 里面,查看,果然能够取到正确的值:

验证完毕后,将正确的值粘贴到代码中,心想,总算解决了。

重新运行一下函数,发现果然能够取到数据了:

但函数依旧卡在这里,并没有继续往下走————超时的问题依旧存在!

现在,愤怒的心情已经没有了,取而代之的是蓝瘦,香菇。站起身,望望窗外,让冷风肆虐你的脸庞。许久,心里平静一些了。

山穷水尽,柳暗花明

冷静下来,理一理线索:

从刚才的调试结果来看,函数已经运行,且获得了正确的结果,但是函数却没有结束,直到超时。突然,一个隐约的答案在你身边徘徊,你拼命想要抓住,来回踱步,蓦地,像是出现了救命稻草一般,打开了函数计算 Nodejs 的 文档,你用尽力气摆动眼球,快速阅读文档,并在心里恳求那根救命稻草的出现。恍然间,你如同穿越了一道厚重的铁门,身边的光线突然由暗变亮,你被这明亮的光线刺的睁不开眼睛。但你知道,答案就在这刺眼的光芒里。眼泪,没能止住,顺着你的脸庞缓慢地流了下来。终于,你松开了紧握的拳头,弯下了一直挺直的腰板,眼泪鼻涕突然倾泻而出,你————失声痛哭。所有的委屈从内心经过喉咙、鼻子、眼睛发泄出来,伴随着这一阵阵渐渐衰弱的回荡声,远去。

哭罢,擦干眼泪,平复下自己的心情,将那一段你追寻许久的答案缓慢但却有力的敲击出来:

callback(null, JSON.parse(body).showapi_res_body.f1.day_weather);

终于,这段代码就如同你家叛逆的孩子,脱去叛逆的伪装,显现出它乖巧的样子:

欲善其事,先利其器

经过这一次事件,你总结出三条经验:

  1. 写代码要耐心、细心,每一段代码都要经过思考。一口气将功能写完,往往是看上去写的快,但实际上会埋很多坑,坑到别人还好,往往不小心会把自己坑了。
  2. 要多读文档。使用语言,要读语言文档,使用第三方库,要读库的文档,使用产品,要读产品文档。如果不仔细阅读仅凭自己的猜测去写,写出的代码往往漏洞百出。男人千万不要硬撑,别对自己这么很。累了要休息,可以读读文档放松下。俗话说得好,磨刀不误砍柴工!
  3. Fun 工具的熟练使用重中之重。 在前两点都没做到的情况下,却能最终将问题排查出来,Fun 工具功不可没!但与之功劳成反比的是,对 Fun 工具的学习尤其是本地调试功能,花的时间反而是最少的,如此巨大的收益比,使自己下定决心,一定要再花些时间,把 Fun 工具 吃透!

总结完,你又用心的看着自己写下的代码,就如同看向自己的孩子,宠溺、疼爱、气愤各种心情夹杂在一起。突然,你一皱眉,呵斥道:这样不对,异常的时候,也要返回!

于是,你纠正了代码的错误行为:

if (error || response.statusCode != 200) {
    console.log("error " + error);
    callback(error, null) ;
} 

就如同,训斥完与人打架的孩子,看到孩子听话了,你露出了欣慰的微笑。

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
2月前
|
运维 Serverless 网络安全
函数计算产品使用问题之通过仓库导入应用时无法配置域名外网访问,该如何排查
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
2月前
|
运维 监控 Serverless
函数计算产品使用问题之超时时间最大是多少
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
2月前
|
前端开发 大数据 数据库
🔥大数据洪流下的决战:JSF 表格组件如何做到毫秒级响应?揭秘背后的性能魔法!💪
【8月更文挑战第31天】在 Web 应用中,表格组件常用于展示和操作数据,但在大数据量下性能会成瓶颈。本文介绍在 JavaServer Faces(JSF)中优化表格组件的方法,包括数据处理、分页及懒加载等技术。通过后端分页或懒加载按需加载数据,减少不必要的数据加载和优化数据库查询,并利用缓存机制减少数据库访问次数,从而提高表格组件的响应速度和整体性能。掌握这些最佳实践对开发高性能 JSF 应用至关重要。
47 0
|
2月前
|
存储 设计模式 运维
Angular遇上Azure Functions:探索无服务器架构下的开发实践——从在线投票系统案例深入分析前端与后端的协同工作
【8月更文挑战第31天】在现代软件开发中,无服务器架构因可扩展性和成本效益而备受青睐。本文通过构建一个在线投票应用,介绍如何结合Angular前端框架与Azure Functions后端服务,快速搭建高效、可扩展的应用系统。Angular提供响应式编程和组件化能力,适合构建动态用户界面;Azure Functions则简化了后端逻辑处理与数据存储。通过具体示例代码,详细展示了从设置Azure Functions到整合Angular前端的全过程,帮助开发者轻松上手无服务器应用开发。
17 0
|
2月前
|
缓存 物联网 Serverless
函数计算产品使用问题之插件无法启用该如何排查问题
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
2月前
|
JavaScript Serverless Linux
函数计算产品使用问题之遇到Node.js环境下的请求日志没有正常输出时,该如何排查
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
3月前
|
运维 Serverless API
Serverless 应用引擎使用问题之如何开发HTTP服务
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
3月前
|
缓存 网络协议 Serverless
函数计算操作报错合集之遇到AxiosError: Network Error错误,该如何排查
在使用函数计算服务(如阿里云函数计算)时,用户可能会遇到多种错误场景。以下是一些常见的操作报错及其可能的原因和解决方法,包括但不限于:1. 函数部署失败、2. 函数执行超时、3. 资源不足错误、4. 权限与访问错误、5. 依赖问题、6. 网络配置错误、7. 触发器配置错误、8. 日志与监控问题。
|
2月前
|
监控 Serverless Go
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
|
2月前
|
Java Serverless Go
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决

相关产品

  • 函数计算
  • 下一篇
    无影云桌面