influxdb/task/backend/coordinator.go

114 lines
2.9 KiB
Go
Raw Normal View History

package backend
import (
"context"
"time"
"github.com/influxdata/influxdb"
"go.uber.org/zap"
)
var now = func() time.Time {
return time.Now().UTC()
}
// TaskService is a type on which tasks can be listed
type TaskService interface {
FindTasks(context.Context, influxdb.TaskFilter) ([]*influxdb.Task, int, error)
UpdateTask(context.Context, influxdb.ID, influxdb.TaskUpdate) (*influxdb.Task, error)
}
// Coordinator is a type with a single method which
// is called when a task has been created
type Coordinator interface {
TaskCreated(context.Context, *influxdb.Task) error
}
// NotifyCoordinatorOfExisting lists all tasks by the provided task service and for
// each task it calls the provided coordinators task created method
func NotifyCoordinatorOfExisting(ctx context.Context, ts TaskService, coord Coordinator, logger *zap.Logger) error {
// If we missed a Create Action
feat(task): Allow tasks to run more isolated from other task systems (#15384) * feat(task): Allow tasks to run more isolated from other task systems To allow the task internal system to be used for user created tasks as well as checks, notification and other future additions we needed to take 2 actions: 1 - We need to use type as a first class citizen, meaning that task's have a type and each system that will be creating tasks will set the task type through the api. This is a change to the previous assumption that any user could set task types. This change will allow us to have other service's white label the task service for their own purposes and not have to worry about colissions between the types. 2 - We needed to allow other systems to add data specific to the problem they are trying to solve. For this purpose adding a `metadata` field to the internal task system which should allow other systems to use the task service. These changes will allow us in the future to allow for the current check's and notifications implementations to create a task with meta data instead of creating a check object and a task object in the database. By allowing this new behavior checks, notifications, and user task's can all follow the same pattern: Field an api request in a system specific http endpoint, use a small translation to the `TaskService` function call, translate the results to what the api expects for this system, and return results. * fix(task): undo additional check for ownerID because check is not ready
2019-10-11 14:53:38 +00:00
tasks, _, err := ts.FindTasks(ctx, influxdb.TaskFilter{})
if err != nil {
return err
}
latestCompleted := now()
for len(tasks) > 0 {
for _, task := range tasks {
if task.Status != string(TaskActive) {
continue
}
task, err := ts.UpdateTask(context.Background(), task.ID, influxdb.TaskUpdate{
LatestCompleted: &latestCompleted,
})
if err != nil {
logger.Error("failed to set latestCompleted", zap.Error(err))
continue
}
coord.TaskCreated(ctx, task)
}
tasks, _, err = ts.FindTasks(ctx, influxdb.TaskFilter{
After: &tasks[len(tasks)-1].ID,
})
if err != nil {
return err
}
}
return nil
}
2019-10-21 19:54:13 +00:00
type TaskResumer func(ctx context.Context, id influxdb.ID, runID influxdb.ID) error
// TaskNotifyCoordinatorOfExisting lists all tasks by the provided task service and for
// each task it calls the provided coordinators task created method
// TODO(docmerlin): this is temporary untill the executor queue is persistent
func TaskNotifyCoordinatorOfExisting(ctx context.Context, ts TaskService, tcs TaskControlService, coord Coordinator, exec TaskResumer, logger *zap.Logger) error {
// If we missed a Create Action
tasks, _, err := ts.FindTasks(ctx, influxdb.TaskFilter{})
if err != nil {
return err
}
latestCompleted := now()
2019-10-21 19:54:13 +00:00
for len(tasks) > 0 {
for _, task := range tasks {
if task.Status != string(TaskActive) {
continue
}
task, err := ts.UpdateTask(context.Background(), task.ID, influxdb.TaskUpdate{
LatestCompleted: &latestCompleted,
})
if err != nil {
logger.Error("failed to set latestCompleted", zap.Error(err))
continue
}
coord.TaskCreated(ctx, task)
runs, err := tcs.CurrentlyRunning(ctx, task.ID)
if err != nil {
return err
}
for i := range runs {
if err := exec(ctx, runs[i].TaskID, runs[i].ID); err != nil {
return err
}
}
}
tasks, _, err = ts.FindTasks(ctx, influxdb.TaskFilter{
After: &tasks[len(tasks)-1].ID,
})
if err != nil {
return err
}
}
return nil
}