Recover from panics in parallel executor workers (#153)

The worker goroutines in `NewParallelExecutor` had no panic recovery. A panic in any executor (e.g. expression evaluation) would crash the entire runner process, leaving all steps stuck in the UI because the final status was never reported back.

Add `defer`/`recover` in the worker goroutines to convert panics into errors that propagate through the normal error channel.

Issue is present in latest `nektos/act` as well.

Fixes https://gitea.com/gitea/act_runner/issues/371

(Partially generated by Claude)

Reviewed-on: https://gitea.com/gitea/act/pulls/153
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-committed-by: silverwind <me@silverwind.io>
This commit is contained in:
silverwind
2026-02-18 03:29:07 +00:00
committed by silverwind
parent c0f19d9a26
commit 43e6958fa3

View File

@@ -3,6 +3,7 @@ package common
import (
"context"
"fmt"
"runtime/debug"
log "github.com/sirupsen/logrus"
)
@@ -110,7 +111,18 @@ func NewParallelExecutor(parallel int, executors ...Executor) Executor {
for executor := range work {
taskCount++
log.Debugf("Worker %d executing task %d", workerID, taskCount)
errs <- executor(ctx)
// Recover from panics in executors to avoid crashing the worker
// goroutine which would leave the runner process hung.
// https://gitea.com/gitea/act_runner/issues/371
errs <- func() (err error) {
defer func() {
if r := recover(); r != nil {
log.Errorf("panic in executor: %v\n%s", r, debug.Stack())
err = fmt.Errorf("panic: %v", r)
}
}()
return executor(ctx)
}()
}
log.Debugf("Worker %d finished (%d tasks executed)", workerID, taskCount)
}(i, work, errs)