运行 在 Jenkins 管道中按顺序执行多个异步步骤的最佳方法
Best approach to run a number of asynchronous steps in sequence in a Jenkins pipeline
让我先简要描述一下我要实现的用例。
上下文
- 我正在使用 Spring Boot 开发服务器应用程序并使用 maven 构建它。
- 该应用程序需要一个 Redis 数据库,因此我可以在构建该应用程序并且 Redis 数据库启动并 运行ning 后启动该应用程序。
- 我正在 JavaScript 中编写我的 REST API 测试,一旦我的应用程序启动,我就可以 运行 它们。
实施
- 对于构建应用程序,不需要任何特殊的东西。我可以简单地做一个
mvn clean install
。我也可以做一个 mvn package
来创建一个可执行的 jar,我可以在 Docker 图像中使用它。
- 对于 运行 应用程序,我使用 Docker Compose 来表达我的应用程序和 Redis 之间的依赖关系。我可以使用
docker-compose up
启动我的环境。 这很好,但它是一个异步步骤:我不知道所有服务完全开始接受请求需要多少时间。
- 当我知道应用程序准备就绪后,我就可以启动我在 JavaScript.
中编写的 API 测试
- 在过程结束时,我可以做一个
docker-compose down
来拆除测试环境。
问题
- 我正在寻求有关处理异步步骤的建议。在这个简化的示例中,有一个步骤:我如何处理 redis 和应用程序需要一些时间(比如 5-15 秒)才能完全启动这一事实?
- Jenkins Pipeline 插件是否有可用于此场景的功能?我无法在教程或文档中找到很多信息。我已经看到
waitUntil
步骤,但我正在寻找一些指导...
- 我是否应该实施一个简单的 shell 脚本,循环向我的应用程序 REST 端点之一发出 HTTP 请求,并在应用程序发送响应后立即完成?我应该在
waitUntil
步骤中调用此脚本吗?
- 是否有更好的方法来满足我的要求?
Should I implement a simple shell script that issues an HTTP request to one of my app REST endpoints in a loop and that completes as soon as the app sends a response? Should I invoke this script in the waitUntil
step?
是的,这是一种合法的方法。
您也可以简单地将其折叠到运行测试的脚本中。为了使流水线脚本简短明了,并且更容易单独测试逻辑片段,请将该脚本存储在 SCM 中。假设它在 Bash 中(但 Python 或任何可以正常工作的东西):
while :
do
if curl http://endpoint/
then
echo Up and running
break
else
echo Still waiting
fi
done
make test
然后您的流水线脚本可以读取类似
的内容
node {
stage 'build'
checkout scm
sh 'mvn clean install'
stage 'test'
sh 'docker-compose up'
try {
sh './run-tests-when-ready'
finally {
sh 'docker-compose down'
}
}
当然,如果您愿意,甚至可以将对 docker-compose
的调用放入此类外部脚本中。在 Bash 中可靠地进行清理很棘手(可以使用 trap EXIT '…'
),在真实语言中更容易。
我最终在我的 Jenkinsfile 中做了这样的事情:
stage 'Validation'
dir("microservice") {
sh "docker-compose down"
sh "docker-compose up &"
}
waitUntil {
def appIsReady = false
try {
echo "Checking Spring Boot status page via ${GAMEDOCK_URL}"
sh "set +e; curl -f -sL -w \"%{http_code}\n\" ${GAMEDOCK_URL} -o /dev/null; echo $? > springBootAppStatus; return 0"
def status = readFile('springBootAppStatus').trim()
echo 'status: ' + status
appIsReady = (status == '0')
} catch (e) {
echo 'exception: ' + e
appIsReady = false
}
echo 'return appIsReady'
return appIsReady == true
}
echo "application is ready"
让我先简要描述一下我要实现的用例。
上下文
- 我正在使用 Spring Boot 开发服务器应用程序并使用 maven 构建它。
- 该应用程序需要一个 Redis 数据库,因此我可以在构建该应用程序并且 Redis 数据库启动并 运行ning 后启动该应用程序。
- 我正在 JavaScript 中编写我的 REST API 测试,一旦我的应用程序启动,我就可以 运行 它们。
实施
- 对于构建应用程序,不需要任何特殊的东西。我可以简单地做一个
mvn clean install
。我也可以做一个mvn package
来创建一个可执行的 jar,我可以在 Docker 图像中使用它。 - 对于 运行 应用程序,我使用 Docker Compose 来表达我的应用程序和 Redis 之间的依赖关系。我可以使用
docker-compose up
启动我的环境。 这很好,但它是一个异步步骤:我不知道所有服务完全开始接受请求需要多少时间。 - 当我知道应用程序准备就绪后,我就可以启动我在 JavaScript. 中编写的 API 测试
- 在过程结束时,我可以做一个
docker-compose down
来拆除测试环境。
问题
- 我正在寻求有关处理异步步骤的建议。在这个简化的示例中,有一个步骤:我如何处理 redis 和应用程序需要一些时间(比如 5-15 秒)才能完全启动这一事实?
- Jenkins Pipeline 插件是否有可用于此场景的功能?我无法在教程或文档中找到很多信息。我已经看到
waitUntil
步骤,但我正在寻找一些指导... - 我是否应该实施一个简单的 shell 脚本,循环向我的应用程序 REST 端点之一发出 HTTP 请求,并在应用程序发送响应后立即完成?我应该在
waitUntil
步骤中调用此脚本吗? - 是否有更好的方法来满足我的要求?
Should I implement a simple shell script that issues an HTTP request to one of my app REST endpoints in a loop and that completes as soon as the app sends a response? Should I invoke this script in the
waitUntil
step?
是的,这是一种合法的方法。
您也可以简单地将其折叠到运行测试的脚本中。为了使流水线脚本简短明了,并且更容易单独测试逻辑片段,请将该脚本存储在 SCM 中。假设它在 Bash 中(但 Python 或任何可以正常工作的东西):
while :
do
if curl http://endpoint/
then
echo Up and running
break
else
echo Still waiting
fi
done
make test
然后您的流水线脚本可以读取类似
的内容node {
stage 'build'
checkout scm
sh 'mvn clean install'
stage 'test'
sh 'docker-compose up'
try {
sh './run-tests-when-ready'
finally {
sh 'docker-compose down'
}
}
当然,如果您愿意,甚至可以将对 docker-compose
的调用放入此类外部脚本中。在 Bash 中可靠地进行清理很棘手(可以使用 trap EXIT '…'
),在真实语言中更容易。
我最终在我的 Jenkinsfile 中做了这样的事情:
stage 'Validation'
dir("microservice") {
sh "docker-compose down"
sh "docker-compose up &"
}
waitUntil {
def appIsReady = false
try {
echo "Checking Spring Boot status page via ${GAMEDOCK_URL}"
sh "set +e; curl -f -sL -w \"%{http_code}\n\" ${GAMEDOCK_URL} -o /dev/null; echo $? > springBootAppStatus; return 0"
def status = readFile('springBootAppStatus').trim()
echo 'status: ' + status
appIsReady = (status == '0')
} catch (e) {
echo 'exception: ' + e
appIsReady = false
}
echo 'return appIsReady'
return appIsReady == true
}
echo "application is ready"