mirror of
https://code.forgejo.org/forgejo/runner.git
synced 2025-09-15 18:57:01 +00:00
fix: add service container health check
Refs: https://github.com/nektos/act/pull/2354/files Signed-off-by: https://github.com/ChristopherHX
This commit is contained in:
parent
8819e2a195
commit
d14092ea56
7 changed files with 94 additions and 2 deletions
|
@ -63,6 +63,7 @@ type Container interface {
|
|||
Remove() common.Executor
|
||||
Close() common.Executor
|
||||
ReplaceLogWriter(io.Writer, io.Writer) (io.Writer, io.Writer)
|
||||
GetHealth(ctx context.Context) Health
|
||||
}
|
||||
|
||||
// NewDockerBuildExecutorInput the input for the NewDockerBuildExecutor function
|
||||
|
@ -82,3 +83,11 @@ type NewDockerPullExecutorInput struct {
|
|||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type Health int
|
||||
|
||||
const (
|
||||
HealthStarting Health = iota
|
||||
HealthHealthy
|
||||
HealthUnHealthy
|
||||
)
|
||||
|
|
|
@ -191,6 +191,30 @@ func (cr *containerReference) Remove() common.Executor {
|
|||
).IfNot(common.Dryrun)
|
||||
}
|
||||
|
||||
func (cr *containerReference) GetHealth(ctx context.Context) Health {
|
||||
resp, err := cr.cli.ContainerInspect(ctx, cr.id)
|
||||
logger := common.Logger(ctx)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to query container health %s", err)
|
||||
return HealthUnHealthy
|
||||
}
|
||||
if resp.Config == nil || resp.Config.Healthcheck == nil || resp.State == nil || resp.State.Health == nil || len(resp.Config.Healthcheck.Test) == 1 && strings.EqualFold(resp.Config.Healthcheck.Test[0], "NONE") {
|
||||
logger.Debugf("no container health check defined")
|
||||
return HealthHealthy
|
||||
}
|
||||
|
||||
logger.Infof("container health of %s (%s) is %s", cr.id, resp.Config.Image, resp.State.Health.Status)
|
||||
switch resp.State.Health.Status {
|
||||
case "starting":
|
||||
return HealthStarting
|
||||
case "healthy":
|
||||
return HealthHealthy
|
||||
case "unhealthy":
|
||||
return HealthUnHealthy
|
||||
}
|
||||
return HealthUnHealthy
|
||||
}
|
||||
|
||||
func (cr *containerReference) ReplaceLogWriter(stdout, stderr io.Writer) (io.Writer, io.Writer) {
|
||||
out := cr.input.Stdout
|
||||
err := cr.input.Stderr
|
||||
|
|
|
@ -493,6 +493,10 @@ func (e *HostEnvironment) GetRunnerContext(_ context.Context) map[string]interfa
|
|||
}
|
||||
}
|
||||
|
||||
func (e *HostEnvironment) GetHealth(ctx context.Context) Health {
|
||||
return HealthHealthy
|
||||
}
|
||||
|
||||
func (e *HostEnvironment) ReplaceLogWriter(stdout, _ io.Writer) (io.Writer, io.Writer) {
|
||||
org := e.StdOut
|
||||
e.StdOut = stdout
|
||||
|
|
|
@ -610,6 +610,7 @@ func (rc *RunContext) startJobContainer() common.Executor {
|
|||
Mode: 0o666,
|
||||
Body: "",
|
||||
}),
|
||||
rc.waitForServiceContainers(),
|
||||
)(ctx)
|
||||
}
|
||||
}
|
||||
|
@ -744,6 +745,40 @@ func (rc *RunContext) startServiceContainers(_ string) common.Executor {
|
|||
}
|
||||
}
|
||||
|
||||
func (rc *RunContext) waitForServiceContainer(c container.ExecutionsEnvironment) common.Executor {
|
||||
return func(ctx context.Context) error {
|
||||
sctx, cancel := context.WithTimeout(ctx, time.Minute*5)
|
||||
defer cancel()
|
||||
var health container.Health
|
||||
delay := time.Second
|
||||
for i := 0; ; i++ {
|
||||
health = c.GetHealth(sctx)
|
||||
if health != container.HealthStarting || i > 30 {
|
||||
break
|
||||
}
|
||||
time.Sleep(delay)
|
||||
delay *= 2
|
||||
if delay > 10*time.Second {
|
||||
delay = 10 * time.Second
|
||||
}
|
||||
}
|
||||
if health == container.HealthHealthy {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("service container failed to start")
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *RunContext) waitForServiceContainers() common.Executor {
|
||||
return func(ctx context.Context) error {
|
||||
execs := []common.Executor{}
|
||||
for _, c := range rc.ServiceContainers {
|
||||
execs = append(execs, rc.waitForServiceContainer(c))
|
||||
}
|
||||
return common.NewParallelExecutor(len(execs), execs...)(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *RunContext) stopServiceContainers() common.Executor {
|
||||
return func(ctx context.Context) error {
|
||||
execs := []common.Executor{}
|
||||
|
|
|
@ -322,6 +322,7 @@ func TestRunner_RunEvent(t *testing.T) {
|
|||
// services
|
||||
{workdir, "services", "push", "", platforms, secrets},
|
||||
{workdir, "services-with-container", "push", "", platforms, secrets},
|
||||
{workdir, "mysql-service-container-with-health-check", "push", "", platforms, secrets},
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
|
|
19
act/runner/testdata/mysql-service-container-with-health-check/push.yml
vendored
Normal file
19
act/runner/testdata/mysql-service-container-with-health-check/push.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
name: service-container
|
||||
on: push
|
||||
jobs:
|
||||
service-container-test:
|
||||
runs-on: ubuntu-latest
|
||||
container: code.forgejo.org/oci/mysql:8.4
|
||||
services:
|
||||
maindb:
|
||||
image: code.forgejo.org/oci/mysql:8.4
|
||||
env:
|
||||
MYSQL_DATABASE: dbname
|
||||
MYSQL_USER: dbuser
|
||||
MYSQL_PASSWORD: dbpass
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: yes
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
steps:
|
||||
- run: mysql -u dbuser -D dbname -pdbpass -h maindb -e "create table T(id INT NOT NULL AUTO_INCREMENT, val VARCHAR(255), PRIMARY KEY (id))"
|
||||
- run: mysql -u dbuser -D dbname -pdbpass -h maindb -e "insert into T(val) values ('test'),('h')"
|
||||
- run: mysql -u dbuser -D dbname -pdbpass -h maindb -e "select * from T"
|
4
act/runner/testdata/services/push.yaml
vendored
4
act/runner/testdata/services/push.yaml
vendored
|
@ -6,7 +6,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: code.forgejo.org/oci/bitnami/postgresql:16
|
||||
image: code.forgejo.org/oci/postgres:16
|
||||
env:
|
||||
POSTGRES_USER: runner
|
||||
POSTGRES_PASSWORD: mysecretdbpass
|
||||
|
@ -15,7 +15,7 @@ jobs:
|
|||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
--health-retries 20
|
||||
ports:
|
||||
- 5432:5432
|
||||
steps:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue