mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-04 12:56:02 +02:00
72 lines
1.6 KiB
Go
72 lines
1.6 KiB
Go
package reconciler
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// RunWithRestart executes execFn.
|
|
// The execution would be restarted, by means of canceling the context provided to execFn, each time restartFn quits.
|
|
// the error returned by restartFn is purely informational and does not affect the execution; may be nil.
|
|
// the loop is stopped when the context provided to RunWithRestart is canceled or a genuine error is returned by execFn, not caused by the context.
|
|
func RunWithRestart(
|
|
ctx context.Context,
|
|
execFn func(context.Context) error,
|
|
restartFn func(context.Context) error,
|
|
) error {
|
|
contexts := make(chan context.Context)
|
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
defer cancel()
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
|
|
var err error
|
|
go func() {
|
|
err = restartWithContext(contexts, execFn)
|
|
cancel()
|
|
wg.Done()
|
|
}()
|
|
go func() {
|
|
restartContexts(ctx, contexts, restartFn)
|
|
wg.Done()
|
|
}()
|
|
|
|
wg.Wait()
|
|
return err
|
|
}
|
|
|
|
func restartContexts(
|
|
base context.Context,
|
|
contexts chan<- context.Context,
|
|
restartFn func(context.Context) error,
|
|
) {
|
|
defer close(contexts)
|
|
for base.Err() == nil {
|
|
ctx, cancel := context.WithCancelCause(base)
|
|
select {
|
|
case contexts <- ctx:
|
|
err := restartFn(ctx)
|
|
cancel(fmt.Errorf("requesting restart: %w", err))
|
|
case <-base.Done():
|
|
cancel(fmt.Errorf("parent context canceled: %w", base.Err()))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func restartWithContext(
|
|
contexts <-chan context.Context,
|
|
execFn func(context.Context) error,
|
|
) error {
|
|
var err error
|
|
for ctx := range contexts {
|
|
err = execFn(ctx)
|
|
if ctx.Err() == nil {
|
|
return err
|
|
}
|
|
}
|
|
return err
|
|
}
|