Skip to content

Commit 3510c5f

Browse files
committed
Extend the Function stage with panic handler support.
Stages can be extended to allow panics to be caught and reported. The panic will still bubble up once the panic handler has resolved.
1 parent 951775d commit 3510c5f

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

pipe/function.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,41 @@ func Function(name string, f StageFunc) Stage {
3232
// goStage is a `Stage` that does its work by running an arbitrary
3333
// `stageFunc` in a goroutine.
3434
type goStage struct {
35-
name string
36-
f StageFunc
37-
done chan struct{}
38-
err error
35+
name string
36+
f StageFunc
37+
done chan struct{}
38+
err error
39+
panicHandler PanicHandler
3940
}
4041

4142
func (s *goStage) Name() string {
4243
return s.name
4344
}
4445

46+
func (s *goStage) SetPanicHandler(ph PanicHandler) {
47+
s.panicHandler = ph
48+
}
49+
4550
func (s *goStage) Start(ctx context.Context, env Env, stdin io.ReadCloser) (io.ReadCloser, error) {
4651
r, w := io.Pipe()
52+
4753
go func() {
54+
defer func() {
55+
if p := recover(); p != nil {
56+
if s.panicHandler == nil {
57+
// Nothing to do, just panic
58+
panic(p)
59+
}
60+
61+
s.err = s.panicHandler(p)
62+
_ = w.Close()
63+
if stdin != nil {
64+
_ = stdin.Close()
65+
}
66+
close(s.done)
67+
}
68+
}()
69+
4870
s.err = s.f(ctx, env, stdin, w)
4971
if err := w.Close(); err != nil && s.err == nil {
5072
s.err = fmt.Errorf("error closing output pipe for stage %q: %w", s.Name(), err)

pipe/panic.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package pipe
2+
3+
// PanicHandlerAware is an interface that stages can implement to receive
4+
// a panic handler from the pipeline.
5+
type PanicHandlerAware interface {
6+
SetPanicHandler(PanicHandler)
7+
}
8+
9+
type PanicHandler func(p any) error

0 commit comments

Comments
 (0)