Gitlab Webhook 的一次问题排查

公司的项目中使用了 Gitlab 来管理代码,在使用 Webhook 自动部署时,我发现前端项目经常会在一个莫名其妙的时间触发 build,通过 commit 记录却发现在这个时间并没有任何人提交代码,而由同一个 Webhook 管理的其他后端项目却没有这个问题。

首先对照了 Gitlab 的官方文档 ,其中描述了 event 的几种类型及数据格式,在我们的测试环境下,需要保证 Feature 提交和 Bug 修复的及时性,因此我只使用了 Push events 来触发 build,但需要注意的是新建分支和 Merge request 仍然会触发 Push event,通过两个参数可以排除不需要 build 的 Push:

  • object_kind 事件的类型,这里只用了 push
  • total_commits_count 提交的次数,次数为 0 的不需要 build

这里并没有发现异常,接着我又新建了一个空的项目,并对各种操作产生的 Webhook 做了日志,最终证明正常情况下的操作不会触发意外的 Webhook,到这个时候,其实我已经有点一筹莫展了,只能硬着头皮从头到尾再读一遍官方文档,看看有没有什么疏漏的地方,最终在文章开始的 Webhook endpoint tips 一节找到了问题的根源,这里我摘抄了过来:

If you are writing your own endpoint (web server) that will receive GitLab webhooks keep in mind the following things:

Your endpoint should send its HTTP response as fast as possible. If you wait too long, GitLab may decide the hook failed and retry it.
Your endpoint should ALWAYS return a valid HTTP response. If you do not do this then GitLab will think the hook failed and retry it. Most HTTP libraries take care of this for you automatically but if you are writing a low-level hook this is important to remember.
GitLab ignores the HTTP status code returned by your endpoint.

结合我们的前端项目来说,Webhook 是由 Gitlab 发起的一次 HTTP 请求,如果这次请求等待 Response 的时间过长或者没有返回 Response,那么 GitLab 会认为这是一次失败的请求,并在某个时间会重新发起请求,由于 Webhook 在调用前端编译命令时并不是异步的,编译时间大概在 5 分钟左右,结果 Gitlab 在请求之后并没有如期收到 Response,于是又重新发起了请求。

找到原因后,解决问题的方法就比较简单了,Webhook 是用 PHP 实现的,可以在收到请求后,在调用编译命令之前执行 fastcgi_finish_request,可以使 Gitlab 很快收到 Response,也就不会出现再发请求的现象了。

这次的问题从根本来说是我的疏忽,没有仔细阅读官方文档,也让我深刻意识到,作为一个开发者,如果项目中使用了他人实现的工具,要想避免入坑,应该对它做一个全面的了解,而不是一知半解。

comments powered by Disqus