Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

🐛 After SIGTERM, `cloudflared tunnel run` uses 100% of one CPU core for the whole graceful-shutdown period

未关闭 适合新手
#1,753 3 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@cyphercodes 已经在做这个了。

开始于 2026年10月8日。

  • #1755 来自 @cyphercodes —— 未关闭
  • #1760 来自 @theolujay —— 未关闭

评估

难度
1/5
预计耗时
1 小时以内
新手友好度
88/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
go
领域
backend

调研方向

issue 指向 supervisor/supervisor.go 中的忙循环,位于 Supervisor.Run 对 gracefulShutdownC 执行的 select 内。阅读该循环以及 waitForSignal 中的信号处理;initialize() 不受影响。验证 SIGTERM 后,supervisor 在排空期间会阻塞,并且在隧道连接结束或宽限期结束时仍会退出。

由索引模型根据 Issue 内容生成。

描述

Priority: Normal Type: Bug

Describe the bug
After SIGTERM, cloudflared tunnel run uses 100% of one CPU core for the whole graceful-shutdown period (up to --grace-period). It uses ~0% before the signal, including while it serves a long-lived request.

The cause is a busy loop in Supervisor.Run (supervisor/supervisor.go). On SIGTERM, waitForSignal calls close(graceShutdownC). The supervisor's main loop selects on that channel:

case <-s.gracefulShutdownC:
    shuttingDown = true

A closed channel is always ready, so this case is selected on every iteration and the for { select { ... } } loop never blocks. The loop runs until the last tunnel connection exits or the process is killed.

To Reproduce

  1. Run a local origin that serves a long-lived response (e.g. an SSE endpoint that writes one event per second for 90s).
  2. Run cloudflared tunnel --grace-period 100s --no-autoupdate --metrics 127.0.0.1:20241 run --token <token>
  3. Open the long-lived request through the tunnel hostname.
  4. kill -TERM <cloudflared pid>
  5. Sample CPU (e.g. /proc/<pid>/stat utime+stime over 3s) or watch top: cloudflared stays at 100% of one core until it exits.
  6. curl '127.0.0.1:20241/debug/pprof/goroutine?debug=2' shows the supervisor goroutine runnable inside the Run select loop, while the rest are blocked.

If it's an issue with Cloudflare Tunnel:
4. Tunnel ID: f499dceb-781e-470b-9943-3c1aa7674c30
5. cloudflared config: no config file; remotely managed tunnel run with --token, --grace-period 100s, --no-autoupdate. Protocol: QUIC (default). The loop is in the supervisor, so it should not depend on the protocol.

Expected behavior
While draining, cloudflared should sit near-idle, blocked until in-flight requests finish or the grace period ends.

Environment and versions

  • OS: Linux (Debian 13 trixie container, kernel 7.1.5)
  • Architecture: AMD64 (x86_64)
  • Version: 2026.9.3 (built 2026-09-24). The same code is on master.

Logs and errors
CPU measured over 3s windows:

idle       cpu%: 0
streaming  cpu%: 0
drain1     cpu%: 100
drain2     cpu%: 100
drain3     cpu%: 101

Log at SIGTERM:

INF Initiating graceful shutdown due to signal terminated ...
INF Unregistered tunnel connection connIndex=2 event=0 ip=198.41.192.7
INF Unregistered tunnel connection connIndex=1 event=0 ip=198.41.192.57

Goroutine dump during drain (54 goroutines; only the pprof handler is running and this one is runnable):

goroutine 61 [runnable]:
context.(*cancelCtx).Done(...)
	/usr/local/go/src/context/context.go:448
github.com/cloudflare/cloudflared/supervisor.(*Supervisor).Run(...)
	.../cloudflared/supervisor/supervisor.go:137 +0x324
github.com/cloudflare/cloudflared/supervisor.StartTunnelDaemon(...)
	.../cloudflared/supervisor/tunnel.go:104 +0x50
github.com/cloudflare/cloudflared/cmd/cloudflared/tunnel.StartServer.func5()
	.../cloudflared/cmd/cloudflared/tunnel/cmd.go:521 +0x74

Additional context
Suggested fix: set the channel to nil after the first receive. A nil channel is never ready in a select, so the loop blocks again.

case <-s.gracefulShutdownC:
    shuttingDown = true
    s.gracefulShutdownC = nil

initialize() also selects on gracefulShutdownC, but it returns immediately on receive, so it is not affected.

Impact: we run cloudflared as the ingress next to our app server and drain for up to 100s on each deploy. During that time cloudflared takes a full core away from the app server while the app server finishes in-flight requests.

主要语言
Go
星标
16.2k
派生
1.5k
PR 合并指标
30 天内没有已合并 PR

环境准备

  • 提供 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

cloudflare/cloudflared 的其他 Issue

查看 cloudflare/cloudflared 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。