如何在自托管GitHub工作流中复用Gradle守护进程
问题描述
每次运行GitHub工作流的Gradle构建步骤时,都会出现如下提示:
Starting a Gradle Daemon, 1 incompatible and 13 stopped Daemons could not be reused, use --status for details
每次构建都会启动新的Gradle守护进程,无法复用空闲进程。当前使用Windows自托管Runner,可修改脚本和环境的任何配置,需要解决两个问题:
- 如何实现空闲守护进程的复用?
- 为何同一项目之前的守护进程会被标记为“不兼容”?
工作流脚本如下(功能:推送main分支时检查版本号变更,若版本与最新标签不匹配则创建新Release):
name: Release on: push: branches: - main jobs: release: runs-on: self-hosted steps: - name: Checkout code run: | git fetch git pull - name: Set up JDK uses: actions/setup-java@v3.13.0 with: distribution: 'adopt' java-version: '21' - name: Build and test run: ./gradlew build - name: Determine version id: determine_version run: | Write-Output "version_num=$(./gradlew -q printVersion)" >> $GITHUB_OUTPUT Write-Output "version=v$version_num" >> $GITHUB_OUTPUT Write-Output "$version" - name: Get previous version id: previous_version run: Write-Output "prev_version=$(git describe --tags $(git rev-list --tags --max-count=1))" >> $GITHUB_OUTPUT - name: Check if version has changed id: version_changed run: Write-Output "changed=${{ steps.determine_version.outputs.version != steps.previous_version.outputs.prev_version }}" >> $GITHUB_OUTPUT - name: Generate release notes id: release_notes if: ${{ steps.version_changed.outputs.changed == 'true' }} run: | Write-Output "release_notes=$(git log $(git describe --tags $(git rev-list --tags --max-count=1))..HEAD --oneline)" >> $GITHUB_OUTPUT - name: Build JAR file id: build_jar if: ${{ steps.version_changed.outputs.changed == 'true' }} run: ./gradlew build - name: Create release id: create_release if: ${{ steps.version_changed.outputs.changed == 'true' }} uses: softprops/action-gh-release@v1 with: files: build/libs/ACSecurity-${{ steps.determine_version.outputs.version_num }}.jar tag_name: ${{ steps.determine_version.outputs.version }} name: ${{ steps.determine_version.outputs.version }} body: | ${ {steps.release_notes.outputs.release_notes} }
解决方案:实现守护进程复用
1. 固定Gradle用户目录,共享缓存与守护进程
GitHub Actions自托管Runner默认会为每个job创建临时工作目录,但Gradle守护进程的状态存储在用户主目录下的.gradle文件夹中。可以在工作流中显式指定统一的GRADLE_USER_HOME,确保所有job共享同一个缓存和守护进程池:
jobs: release: runs-on: self-hosted env: GRADLE_USER_HOME: C:\gradle-shared-cache # 固定路径,确保Runner有读写权限 # 或者使用Runner工作区的固定子目录:${{ runner.workspace }}/.gradle
2. 保证JDK环境完全一致
actions/setup-java默认会将JDK下载到临时目录,每次job的JDK路径可能不同,导致Gradle认为守护进程不兼容。可以指定固定的JDK安装路径,或者让setup-java使用本地已安装的JDK:
- name: Set up JDK uses: actions/setup-java@v3.13.0 with: distribution: 'adopt' java-version: '21' java-package: jdk architecture: x64 cache: gradle # 启用Gradle缓存,同时稳定JDK环境
另外,确保Runner上的JDK版本固定,避免每次下载不同的构建包。
3. 延长守护进程空闲存活时间
在项目根目录的gradle.properties或全局的%USERPROFILE%\.gradle\gradle.properties中添加以下配置,让空闲守护进程存活更久:
org.gradle.daemon.idletimeout=3600000 # 空闲1小时后再停止,默认是10分钟 org.gradle.daemon.maxIdleTime=7200000 # 最大空闲存活2小时
4. 合并Gradle任务,减少启动次数
你的工作流中两次调用./gradlew build,可以合并成一次调用,避免多次启动守护进程。比如将构建、测试和版本号获取合并:
- name: Build, test and retrieve version id: build_version run: | ./gradlew build $version_num = ./gradlew -q printVersion Write-Output "version_num=$version_num" >> $GITHUB_OUTPUT Write-Output "version=v$version_num" >> $GITHUB_OUTPUT
这样只需要启动一次Gradle守护进程,完成多个任务。
为什么之前的守护进程会显示“不兼容”
Gradle守护进程的兼容性由多个核心因素决定,只要有一项不匹配就会被标记为无法复用:
- JDK版本/路径:如果之前的守护进程是用不同版本的JDK,或者相同版本但安装路径不同(比如setup-java每次下载到临时目录),Gradle会判定不兼容。这是最常见的原因。
- Gradle版本:项目的Gradle Wrapper版本变化,会导致守护进程无法复用。
- 环境变量:
JAVA_HOME、GRADLE_USER_HOME等关键环境变量变更,会让Gradle启动新的守护进程。 - 项目配置:
build.gradle或settings.gradle中的重大配置变更,也可能导致守护进程不兼容,但这种情况较少见。
你提到是同一项目的之前构建,大概率是JDK路径的变化导致的——每次setup-java都下载新的JDK到临时目录,使得JAVA_HOME不同,从而让Gradle认为之前的守护进程与当前环境不兼容。
内容的提问来源于stack exchange,提问作者ThrownRedstone

