mirror of
https://github.com/owncloud/ocis
synced 2026-04-25 17:25:21 +02:00
94 lines
2.9 KiB
Go
94 lines
2.9 KiB
Go
package runner
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
StopSignals = []os.Signal{syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT}
|
|
)
|
|
|
|
// Runable represent a task that can be executed by the Runner.
|
|
// It expected to be a long running task with an indefinite execution time,
|
|
// so it's suitable for servers or services.
|
|
// The task can eventually return an error, or nil if the execution finishes
|
|
// without errors
|
|
type Runable func() error
|
|
|
|
// Stopper represent a function that will stop the Runable.
|
|
// The stopper acts as a notification to the runable to know that the task
|
|
// needs to be finished now.
|
|
//
|
|
// The stopper won't need to crash the runable or force the runable to stop,
|
|
// instead, it will let the runable to know it has to stop and let it finish.
|
|
// This means that the runable might still run for a while.
|
|
//
|
|
// It's recommended the stopper to run asynchronously. This means that the
|
|
// stopper might need to spawn a goroutine. The intention is avoid blocking
|
|
// the running thread.
|
|
//
|
|
// Usually, the stoppers are the servers's `Shutdown()` or `Close()` methods,
|
|
// that will cause the server to start its shutdown procedure. As said, there
|
|
// is no need to force the shutdown, so graceful shutdowns are preferred if
|
|
// they're available
|
|
type Stopper func()
|
|
|
|
// Result represents the result of a runner.
|
|
// The result contains the provided runner's id (for easier identification
|
|
// in case of multiple results) and the runner's error, which is the result
|
|
// of the Runable function (might be nil if no error happened)
|
|
type Result struct {
|
|
RunnerID string
|
|
RunnerError error
|
|
}
|
|
|
|
// FormatError formats the error of the result.
|
|
// If the error is nil, it returns nil
|
|
func (r *Result) FormatError() error {
|
|
if r.RunnerError != nil {
|
|
return fmt.Errorf("runner %s failed: %w", r.RunnerID, r.RunnerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TimeoutError is an error that should be used for timeouts.
|
|
// It implements the `error` interface
|
|
type TimeoutError struct {
|
|
RunnerID string
|
|
Duration time.Duration
|
|
}
|
|
|
|
// NewTimeoutError creates a new timeout error. Both runnerID and duration
|
|
// will be used in the error message
|
|
func NewTimeoutError(runnerID string, duration time.Duration) *TimeoutError {
|
|
return &TimeoutError{
|
|
RunnerID: runnerID,
|
|
Duration: duration,
|
|
}
|
|
}
|
|
|
|
// NewGroupTimeoutError creates a new timeout error. This is intended to be
|
|
// used for group runners when the timeout of the group is reached.
|
|
// The runner id will be set to "_unknown_" because we don't know which is
|
|
// the id of the missing runner.
|
|
func NewGroupTimeoutError(duration time.Duration) *TimeoutError {
|
|
return &TimeoutError{
|
|
RunnerID: "_unknown_",
|
|
Duration: duration,
|
|
}
|
|
}
|
|
|
|
// Error generates the message for this particular error.
|
|
func (te *TimeoutError) Error() string {
|
|
var sb strings.Builder
|
|
sb.WriteString("Runner ")
|
|
sb.WriteString(te.RunnerID)
|
|
sb.WriteString(" timed out after waiting for ")
|
|
sb.WriteString(te.Duration.String())
|
|
return sb.String()
|
|
}
|