func WithBackoff(limit int) StartOpt {
	return func(opts *startOptions) {
		opts.Modifier = append(opts.Modifier, func(j *corev1.Pod) {
			opts.BackoffLimit = limit
		})
	}
}
WithBackoff configures the backoff behaviour of a job
package executor
import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
	werftv1 "github.com/csweichel/werft/pkg/api/v1"
	"github.com/gogo/protobuf/jsonpb"
	"github.com/golang/protobuf/ptypes"
	log "github.com/sirupsen/logrus"
	"github.com/technosophos/moniker"
	"golang.org/x/xerrors"
	corev1 "k8s.io/api/core/v1"
	k8serr "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/util/retry"
)
type Config struct {
	Namespace       string    `yaml:"namespace"`
	EventTraceLog   string    `yaml:"eventTraceLog,omitempty"`
	JobPrepTimeout  *Duration `yaml:"preperationTimeout"`
	JobTotalTimeout *Duration `yaml:"totalTimeout"`
	LabelPrefix     string    `json:"labelPrefix"`
}
type Duration struct {
	time.Duration
}
func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var v string
	err := unmarshal(&v)
	if err != nil {
		return err
	}
	d.Duration, err = time.ParseDuration(v)
	if err != nil {
		return err
	}
	return nil
}
func NewExecutor(config Config, kubeConfig *rest.Config) (*Executor, error) {
	kubeClient, err := kubernetes.NewForConfig(kubeConfig)
	if err != nil {
		return nil, err
	}
	if config.JobPrepTimeout == nil {
		return nil, xerrors.Errorf("job preperation timeout is required")
	}
	if config.JobTotalTimeout == nil {
		return nil, xerrors.Errorf("total job timeout is required")
	}
	if config.JobTotalTimeout.Duration < config.JobPrepTimeout.Duration {
		return nil, xerrors.Errorf("total job timeout must be greater than the preparation timeout")
	}
	return &Executor{
		OnUpdate: func(pod *corev1.Pod, status *werftv1.JobStatus) {},
		Config:     config,
		Client:     kubeClient,
		KubeConfig: kubeConfig,
		labels:      newLabelSetet(config.LabelPrefix),
		waitingJobs: make(map[string]*waitingJob),
	}, nil
}
type Executor struct {
	OnUpdate func(pod *corev1.Pod, status *werftv1.JobStatus)
	Client     kubernetes.Interface
	Config     Config
	KubeConfig *rest.Config
	labels      labelSet
	waitingJobs map[string]*waitingJob
	mu          sync.RWMutex
}
type waitingJob struct {
	Cancel func(reason string)
	Start  func()
	Mutex  string
	Status *werftv1.JobStatus
}
func (js *Executor) Run() {
	go js.monitorJobs()
	go js.doHousekeeping()
}
type startOptions struct {
	JobName      string
	Modifier     []func(*corev1.Pod)
	Annotations  map[string]string
	BackoffLimit int
	Mutex        string
	CanReplay    bool
	WaitUntil    time.Time
	Sidecars     []string
}
type StartOpt func(*startOptions)