AWS Lambda部署Go+chromedp遇WebSocket超时问题排查
问题:AWS Lambda部署chromedp时WebSocket URL超时错误
我用Go开发AWS Lambda服务,通过Docker镜像部署集成chromedp的代码时,碰到WebSocket URL超时错误。当前Lambda配置:3008MB内存、512MB存储、15分钟超时时间。以下是相关代码和Dockerfile,求排查问题并给出修复方案。
相关代码文件
main.go(chromedp部分)
func getPage(URL string, lineNum string, stationNm string) { // settings for crawling ctx, cancle := chromedp.NewContext( context.Background(), chromedp.WithLogf(log.Printf), ) defer cancle() opts := []chromedp.ExecAllocatorOption{ chromedp.DisableGPU, chromedp.NoSandbox, chromedp.Headless, chromedp.Flag("no-zygote", true), chromedp.Flag("single-process", true), chromedp.Flag("homedir", "/tmp"), chromedp.Flag("data-path", "/tmp/data-path"), chromedp.Flag("disk-cache-dir", "/tmp/cache-dir"), chromedp.Flag("remote-debugging-port", "9222"), chromedp.Flag("remote-debugging-address", "0.0.0.0"), chromedp.Flag("disable-dev-shm-usage", true), } allocCtx, cancel := chromedp.NewExecAllocator(ctx, opts...) defer cancel() ctx, cancel = chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf)) defer cancel() var htmlContent string ch := chromedp.WaitNewTarget(ctx, func(i *target.Info) bool { return strings.Contains(i.URL, "/timetable/web/") }) }
Dockerfile
FROM public.ecr.aws/lambda/provided:al2 AS build ENV GO111MODULE=on \ CGO_ENABLED=0 \ GOOS=linux \ GOARCH=amd64 # Get rid of the extension warning RUN mkdir -p /opt/extensions RUN yum -y install golang RUN go env -w GOPROXY=direct # Clone git, copying go.mod, go.sum, main.go WORKDIR /var/task/ RUN yum install git -y RUN git clone https://github.com/seedspirit/NaverCrawler-CICD-go.git RUN cp NaverCrawler-CICD-go/main.go /var/task/ RUN cp NaverCrawler-CICD-go/go.mod /var/task/ RUN cp NaverCrawler-CICD-go/go.sum /var/task/ # cache dependencies RUN go mod download RUN go build -o main . FROM public.ecr.aws/lambda/provided:al2 COPY --from=build /var/task/main /var/task/main # Install Chrome dependencies RUN curl https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm -o chrome.rpm && \ yum install -y ./chrome.rpm && \ yum install -y fontconfig libX11 GConf2 dbus-x11 ENTRYPOINT ["/var/task/main"]
排查分析
- 上下文初始化顺序错误:先创建chromedp上下文再创建执行分配器,导致指定的Chrome启动参数无法生效,chromedp无法正确连接Chrome的调试端口,引发WebSocket超时。
- Chrome启动参数冲突:
single-process参数在Lambda隔离环境中易导致Chrome启动不稳定;手动指定remote-debugging-port=9222可能引发端口占用问题,chromedp默认会自动分配可用端口,无需手动指定。 - Docker镜像依赖不全:Amazon Linux 2上安装Chrome后缺少部分必要依赖(如
libXext、libXtst),导致Chrome启动失败,间接触发WebSocket连接超时。 - 无超时的阻塞逻辑:代码中调用
chromedp.WaitNewTarget后未设置超时处理,若目标未出现会一直阻塞,最终触发Lambda超时。
修复方案
1. 修正chromedp上下文初始化逻辑
调整顺序,先创建执行分配器再生成chromedp上下文,同时移除冲突参数、增加超时控制:
import ( "context" "log" "strings" "time" "github.com/chromedp/chromedp" "github.com/chromedp/chromedp/kb" ) func getPage(URL string, lineNum string, stationNm string) error { // 定义Chrome启动参数,移除冲突项 opts := []chromedp.ExecAllocatorOption{ chromedp.DisableGPU, chromedp.NoSandbox, chromedp.Headless, chromedp.Flag("no-zygote", true), chromedp.Flag("disable-dev-shm-usage", true), chromedp.Flag("homedir", "/tmp"), chromedp.Flag("data-path", "/tmp/data-path"), chromedp.Flag("disk-cache-dir", "/tmp/cache-dir"), // 移除手动指定调试端口和单进程参数 } // 先创建执行分配器上下文 allocCtx, cancelAlloc := chromedp.NewExecAllocator(context.Background(), opts...) defer cancelAlloc() // 基于分配器创建chromedp上下文 ctx, cancelCtx := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf)) defer cancelCtx() // 设置上下文超时,避免无限阻塞 ctx, cancelTimeout := context.WithTimeout(ctx, 5*time.Minute) defer cancelTimeout() var htmlContent string // 先执行页面导航,确保Chrome正常启动 if err := chromedp.Run(ctx, chromedp.Navigate(URL), chromedp.WaitVisible("body", chromedp.ByQuery), ); err != nil { return err } // 带超时处理的目标等待逻辑 select { case target := <-chromedp.WaitNewTarget(ctx, func(i *chromedp.Target) bool { return strings.Contains(i.URL, "/timetable/web/") }): log.Printf("匹配到目标页面: %s", target.URL) // 切换到目标页面并获取内容 if err := chromedp.Run(ctx, chromedp.SwitchTarget(target), chromedp.OuterHTML("body", &htmlContent, chromedp.ByQuery), ); err != nil { return err } case <-ctx.Done(): return ctx.Err() // 返回超时或取消错误 } // 后续处理htmlContent... return nil }
2. 完善Dockerfile的Chrome依赖
补充安装缺失的系统依赖,确保Chrome能正常启动:
FROM public.ecr.aws/lambda/provided:al2 AS build ENV GO111MODULE=on \ CGO_ENABLED=0 \ GOOS=linux \ GOARCH=amd64 RUN mkdir -p /opt/extensions RUN yum -y install golang RUN go env -w GOPROXY=direct WORKDIR /var/task/ RUN yum install git -y RUN git clone https://github.com/seedspirit/NaverCrawler-CICD-go.git RUN cp NaverCrawler-CICD-go/main.go /var/task/ RUN cp NaverCrawler-CICD-go/go.mod /var/task/ RUN cp NaverCrawler-CICD-go/go.sum /var/task/ RUN go mod download RUN go build -o main . FROM public.ecr.aws/lambda/provided:al2 COPY --from=build /var/task/main /var/task/main # 安装Chrome及完整依赖包 RUN curl https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm -o chrome.rpm && \ yum install -y ./chrome.rpm && \ yum install -y fontconfig libX11 GConf2 dbus-x11 libXext libXtst libXScrnSaver libXrandr alsa-lib && \ yum clean all && rm -f ./chrome.rpm ENTRYPOINT ["/var/task/main"]
3. Lambda配置优化
- 存储调整:将Lambda存储从512MB提升至1024MB,Chrome会在
/tmp目录生成大量缓存文件,更大的存储能避免磁盘空间不足导致的启动失败。 - 日志权限:确保Lambda执行角色拥有
CloudWatchLogsFullAccess权限,方便查看Chrome启动和chromedp运行的详细日志。
内容的提问来源于stack exchange,提问作者kim
相关产品推荐
相关产品推荐

