117 lines
3.8 KiB
Go
117 lines
3.8 KiB
Go
package backend
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/influxdata/influxdb"
|
|
)
|
|
|
|
// TaskControlService is a low-level controller interface, intended to be passed to
|
|
// task executors and schedulers, which allows creation, completion, and status updates of runs.
|
|
type TaskControlService interface {
|
|
// CreateNextRun attempts to create a new run.
|
|
// The new run's ScheduledFor is assigned the earliest possible time according to task's cron,
|
|
// that is later than any in-progress run and LatestCompleted run.
|
|
// If the run's ScheduledFor would be later than the passed-in now, CreateNextRun returns an ErrRunNotDueYet.
|
|
CreateNextRun(ctx context.Context, taskID influxdb.ID, now int64) (RunCreation, error)
|
|
|
|
// NextDueRun returns the Unix timestamp of when the next call to CreateNextRun will be ready.
|
|
// The returned timestamp reflects the task's offset, so it does not necessarily exactly match the schedule time.
|
|
NextDueRun(ctx context.Context, taskID influxdb.ID) (int64, error)
|
|
|
|
// CreateRun creates a run with a schedule for time.
|
|
// This differes from CreateNextRun in that it should not to use some scheduling system to determin when the run
|
|
// should happen.
|
|
// TODO(lh): remove comment once we no longer need create next run.
|
|
CreateRun(ctx context.Context, taskID influxdb.ID, scheduledFor time.Time) (*influxdb.Run, error)
|
|
|
|
CurrentlyRunning(ctx context.Context, taskID influxdb.ID) ([]*influxdb.Run, error)
|
|
ManualRuns(ctx context.Context, taskID influxdb.ID) ([]*influxdb.Run, error)
|
|
|
|
// StartManualRun pulls a manual run from the list and moves it to currently running.
|
|
StartManualRun(ctx context.Context, taskID, runID influxdb.ID) (*influxdb.Run, error)
|
|
|
|
// FinishRun removes runID from the list of running tasks and if its `ScheduledFor` is later then last completed update it.
|
|
FinishRun(ctx context.Context, taskID, runID influxdb.ID) (*influxdb.Run, error)
|
|
|
|
// UpdateRunState sets the run state at the respective time.
|
|
UpdateRunState(ctx context.Context, taskID, runID influxdb.ID, when time.Time, state RunStatus) error
|
|
|
|
// AddRunLog adds a log line to the run.
|
|
AddRunLog(ctx context.Context, taskID, runID influxdb.ID, when time.Time, log string) error
|
|
}
|
|
|
|
type TaskStatus string
|
|
|
|
const (
|
|
TaskActive TaskStatus = "active"
|
|
TaskInactive TaskStatus = "inactive"
|
|
|
|
DefaultTaskStatus TaskStatus = TaskActive
|
|
)
|
|
|
|
type RunStatus int
|
|
|
|
const (
|
|
RunStarted RunStatus = iota
|
|
RunSuccess
|
|
RunFail
|
|
RunCanceled
|
|
RunScheduled
|
|
)
|
|
|
|
func (r RunStatus) String() string {
|
|
switch r {
|
|
case RunStarted:
|
|
return "started"
|
|
case RunSuccess:
|
|
return "success"
|
|
case RunFail:
|
|
return "failed"
|
|
case RunCanceled:
|
|
return "canceled"
|
|
case RunScheduled:
|
|
return "scheduled"
|
|
}
|
|
panic(fmt.Sprintf("unknown RunStatus: %d", r))
|
|
}
|
|
|
|
// RequestStillQueuedError is returned when attempting to retry a run which has not yet completed.
|
|
type RequestStillQueuedError struct {
|
|
// Unix timestamps matching existing request's start and end.
|
|
Start, End int64
|
|
}
|
|
|
|
const fmtRequestStillQueued = "previous retry for start=%s end=%s has not yet finished"
|
|
|
|
func (e RequestStillQueuedError) Error() string {
|
|
return fmt.Sprintf(fmtRequestStillQueued,
|
|
time.Unix(e.Start, 0).UTC().Format(time.RFC3339),
|
|
time.Unix(e.End, 0).UTC().Format(time.RFC3339),
|
|
)
|
|
}
|
|
|
|
// ParseRequestStillQueuedError attempts to parse a RequestStillQueuedError from msg.
|
|
// If msg is formatted correctly, the resultant error is returned; otherwise it returns nil.
|
|
func ParseRequestStillQueuedError(msg string) *RequestStillQueuedError {
|
|
var s, e string
|
|
n, err := fmt.Sscanf(msg, fmtRequestStillQueued, &s, &e)
|
|
if err != nil || n != 2 {
|
|
return nil
|
|
}
|
|
|
|
start, err := time.Parse(time.RFC3339, s)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
end, err := time.Parse(time.RFC3339, e)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
return &RequestStillQueuedError{Start: start.Unix(), End: end.Unix()}
|
|
}
|