Transition from ex-GORM structs to sqlc structs (2/5)
Replace old used-to-be-GORM datastructures (#104305) with sqlc-generated structs. This also makes it possible to use more specific structs that are more taylored to the specific queries, increasing efficiency. This commit mostly deals with workers, including the sleep schedule and task scheduler. Functional changes are kept to a minimum, as the API still serves the same data. Because this work covers so much of Flamenco's code, it's been split up into different commits. Each commit brings Flamenco to a state where it compiles and unit tests pass. Only the result of the final commit has actually been tested properly. Ref: #104343
This commit is contained in:
parent
94d71bc3c9
commit
84f93e7502
@ -76,6 +76,7 @@ type PersistenceService interface {
|
|||||||
FetchWorkerTags(ctx context.Context) ([]*persistence.WorkerTag, error)
|
FetchWorkerTags(ctx context.Context) ([]*persistence.WorkerTag, error)
|
||||||
DeleteWorkerTag(ctx context.Context, uuid string) error
|
DeleteWorkerTag(ctx context.Context, uuid string) error
|
||||||
SaveWorkerTag(ctx context.Context, tag *persistence.WorkerTag) error
|
SaveWorkerTag(ctx context.Context, tag *persistence.WorkerTag) error
|
||||||
|
FetchTagsOfWorker(ctx context.Context, workerUUID string) ([]persistence.WorkerTag, error)
|
||||||
|
|
||||||
// WorkersLeftToRun returns a set of worker UUIDs that can run tasks of the given type on the given job.
|
// WorkersLeftToRun returns a set of worker UUIDs that can run tasks of the given type on the given job.
|
||||||
WorkersLeftToRun(ctx context.Context, job *persistence.Job, taskType string) (map[string]bool, error)
|
WorkersLeftToRun(ctx context.Context, job *persistence.Job, taskType string) (map[string]bool, error)
|
||||||
|
51
internal/manager/api_impl/mocks/api_impl_mock.gen.go
generated
51
internal/manager/api_impl/mocks/api_impl_mock.gen.go
generated
@ -44,7 +44,7 @@ func (m *MockPersistenceService) EXPECT() *MockPersistenceServiceMockRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddWorkerToJobBlocklist mocks base method.
|
// AddWorkerToJobBlocklist mocks base method.
|
||||||
func (m *MockPersistenceService) AddWorkerToJobBlocklist(arg0 context.Context, arg1 *persistence.Job, arg2 *persistence.Worker, arg3 string) error {
|
func (m *MockPersistenceService) AddWorkerToJobBlocklist(arg0 context.Context, arg1 *persistence.Job, arg2 *sqlc.Worker, arg3 string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "AddWorkerToJobBlocklist", arg0, arg1, arg2, arg3)
|
ret := m.ctrl.Call(m, "AddWorkerToJobBlocklist", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -58,7 +58,7 @@ func (mr *MockPersistenceServiceMockRecorder) AddWorkerToJobBlocklist(arg0, arg1
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddWorkerToTaskFailedList mocks base method.
|
// AddWorkerToTaskFailedList mocks base method.
|
||||||
func (m *MockPersistenceService) AddWorkerToTaskFailedList(arg0 context.Context, arg1 *persistence.Task, arg2 *persistence.Worker) (int, error) {
|
func (m *MockPersistenceService) AddWorkerToTaskFailedList(arg0 context.Context, arg1 *persistence.Task, arg2 *sqlc.Worker) (int, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "AddWorkerToTaskFailedList", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "AddWorkerToTaskFailedList", arg0, arg1, arg2)
|
||||||
ret0, _ := ret[0].(int)
|
ret0, _ := ret[0].(int)
|
||||||
@ -115,7 +115,7 @@ func (mr *MockPersistenceServiceMockRecorder) ClearJobBlocklist(arg0, arg1 inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CountTaskFailuresOfWorker mocks base method.
|
// CountTaskFailuresOfWorker mocks base method.
|
||||||
func (m *MockPersistenceService) CountTaskFailuresOfWorker(arg0 context.Context, arg1 *persistence.Job, arg2 *persistence.Worker, arg3 string) (int, error) {
|
func (m *MockPersistenceService) CountTaskFailuresOfWorker(arg0 context.Context, arg1 *persistence.Job, arg2 *sqlc.Worker, arg3 string) (int, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "CountTaskFailuresOfWorker", arg0, arg1, arg2, arg3)
|
ret := m.ctrl.Call(m, "CountTaskFailuresOfWorker", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].(int)
|
ret0, _ := ret[0].(int)
|
||||||
@ -130,7 +130,7 @@ func (mr *MockPersistenceServiceMockRecorder) CountTaskFailuresOfWorker(arg0, ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateWorker mocks base method.
|
// CreateWorker mocks base method.
|
||||||
func (m *MockPersistenceService) CreateWorker(arg0 context.Context, arg1 *persistence.Worker) error {
|
func (m *MockPersistenceService) CreateWorker(arg0 context.Context, arg1 *sqlc.Worker) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "CreateWorker", arg0, arg1)
|
ret := m.ctrl.Call(m, "CreateWorker", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -230,6 +230,21 @@ func (mr *MockPersistenceServiceMockRecorder) FetchJobs(arg0 interface{}) *gomoc
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchJobs", reflect.TypeOf((*MockPersistenceService)(nil).FetchJobs), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchJobs", reflect.TypeOf((*MockPersistenceService)(nil).FetchJobs), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchTagsOfWorker mocks base method.
|
||||||
|
func (m *MockPersistenceService) FetchTagsOfWorker(arg0 context.Context, arg1 string) ([]persistence.WorkerTag, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "FetchTagsOfWorker", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].([]persistence.WorkerTag)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchTagsOfWorker indicates an expected call of FetchTagsOfWorker.
|
||||||
|
func (mr *MockPersistenceServiceMockRecorder) FetchTagsOfWorker(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchTagsOfWorker", reflect.TypeOf((*MockPersistenceService)(nil).FetchTagsOfWorker), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// FetchTask mocks base method.
|
// FetchTask mocks base method.
|
||||||
func (m *MockPersistenceService) FetchTask(arg0 context.Context, arg1 string) (*persistence.Task, error) {
|
func (m *MockPersistenceService) FetchTask(arg0 context.Context, arg1 string) (*persistence.Task, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -246,10 +261,10 @@ func (mr *MockPersistenceServiceMockRecorder) FetchTask(arg0, arg1 interface{})
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchTaskFailureList mocks base method.
|
// FetchTaskFailureList mocks base method.
|
||||||
func (m *MockPersistenceService) FetchTaskFailureList(arg0 context.Context, arg1 *persistence.Task) ([]*persistence.Worker, error) {
|
func (m *MockPersistenceService) FetchTaskFailureList(arg0 context.Context, arg1 *persistence.Task) ([]*sqlc.Worker, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchTaskFailureList", arg0, arg1)
|
ret := m.ctrl.Call(m, "FetchTaskFailureList", arg0, arg1)
|
||||||
ret0, _ := ret[0].([]*persistence.Worker)
|
ret0, _ := ret[0].([]*sqlc.Worker)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
@ -276,10 +291,10 @@ func (mr *MockPersistenceServiceMockRecorder) FetchTaskJobUUID(arg0, arg1 interf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchWorker mocks base method.
|
// FetchWorker mocks base method.
|
||||||
func (m *MockPersistenceService) FetchWorker(arg0 context.Context, arg1 string) (*persistence.Worker, error) {
|
func (m *MockPersistenceService) FetchWorker(arg0 context.Context, arg1 string) (*sqlc.Worker, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchWorker", arg0, arg1)
|
ret := m.ctrl.Call(m, "FetchWorker", arg0, arg1)
|
||||||
ret0, _ := ret[0].(*persistence.Worker)
|
ret0, _ := ret[0].(*sqlc.Worker)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
@ -321,7 +336,7 @@ func (mr *MockPersistenceServiceMockRecorder) FetchWorkerTags(arg0 interface{})
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchWorkerTask mocks base method.
|
// FetchWorkerTask mocks base method.
|
||||||
func (m *MockPersistenceService) FetchWorkerTask(arg0 context.Context, arg1 *persistence.Worker) (*persistence.Task, error) {
|
func (m *MockPersistenceService) FetchWorkerTask(arg0 context.Context, arg1 *sqlc.Worker) (*persistence.Task, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchWorkerTask", arg0, arg1)
|
ret := m.ctrl.Call(m, "FetchWorkerTask", arg0, arg1)
|
||||||
ret0, _ := ret[0].(*persistence.Task)
|
ret0, _ := ret[0].(*persistence.Task)
|
||||||
@ -336,10 +351,10 @@ func (mr *MockPersistenceServiceMockRecorder) FetchWorkerTask(arg0, arg1 interfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchWorkers mocks base method.
|
// FetchWorkers mocks base method.
|
||||||
func (m *MockPersistenceService) FetchWorkers(arg0 context.Context) ([]*persistence.Worker, error) {
|
func (m *MockPersistenceService) FetchWorkers(arg0 context.Context) ([]*sqlc.Worker, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchWorkers", arg0)
|
ret := m.ctrl.Call(m, "FetchWorkers", arg0)
|
||||||
ret0, _ := ret[0].([]*persistence.Worker)
|
ret0, _ := ret[0].([]*sqlc.Worker)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
@ -423,7 +438,7 @@ func (mr *MockPersistenceServiceMockRecorder) SaveTaskActivity(arg0, arg1 interf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveWorker mocks base method.
|
// SaveWorker mocks base method.
|
||||||
func (m *MockPersistenceService) SaveWorker(arg0 context.Context, arg1 *persistence.Worker) error {
|
func (m *MockPersistenceService) SaveWorker(arg0 context.Context, arg1 *sqlc.Worker) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "SaveWorker", arg0, arg1)
|
ret := m.ctrl.Call(m, "SaveWorker", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -437,7 +452,7 @@ func (mr *MockPersistenceServiceMockRecorder) SaveWorker(arg0, arg1 interface{})
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveWorkerStatus mocks base method.
|
// SaveWorkerStatus mocks base method.
|
||||||
func (m *MockPersistenceService) SaveWorkerStatus(arg0 context.Context, arg1 *persistence.Worker) error {
|
func (m *MockPersistenceService) SaveWorkerStatus(arg0 context.Context, arg1 *sqlc.Worker) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "SaveWorkerStatus", arg0, arg1)
|
ret := m.ctrl.Call(m, "SaveWorkerStatus", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -465,7 +480,7 @@ func (mr *MockPersistenceServiceMockRecorder) SaveWorkerTag(arg0, arg1 interface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ScheduleTask mocks base method.
|
// ScheduleTask mocks base method.
|
||||||
func (m *MockPersistenceService) ScheduleTask(arg0 context.Context, arg1 *persistence.Worker) (*persistence.Task, error) {
|
func (m *MockPersistenceService) ScheduleTask(arg0 context.Context, arg1 *sqlc.Worker) (*persistence.Task, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "ScheduleTask", arg0, arg1)
|
ret := m.ctrl.Call(m, "ScheduleTask", arg0, arg1)
|
||||||
ret0, _ := ret[0].(*persistence.Task)
|
ret0, _ := ret[0].(*persistence.Task)
|
||||||
@ -522,7 +537,7 @@ func (mr *MockPersistenceServiceMockRecorder) TaskTouchedByWorker(arg0, arg1 int
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WorkerSeen mocks base method.
|
// WorkerSeen mocks base method.
|
||||||
func (m *MockPersistenceService) WorkerSeen(arg0 context.Context, arg1 *persistence.Worker) error {
|
func (m *MockPersistenceService) WorkerSeen(arg0 context.Context, arg1 *sqlc.Worker) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "WorkerSeen", arg0, arg1)
|
ret := m.ctrl.Call(m, "WorkerSeen", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -536,7 +551,7 @@ func (mr *MockPersistenceServiceMockRecorder) WorkerSeen(arg0, arg1 interface{})
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WorkerSetTags mocks base method.
|
// WorkerSetTags mocks base method.
|
||||||
func (m *MockPersistenceService) WorkerSetTags(arg0 context.Context, arg1 *persistence.Worker, arg2 []string) error {
|
func (m *MockPersistenceService) WorkerSetTags(arg0 context.Context, arg1 *sqlc.Worker, arg2 []string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "WorkerSetTags", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "WorkerSetTags", arg0, arg1, arg2)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -1017,7 +1032,7 @@ func (mr *MockTaskStateMachineMockRecorder) JobStatusChange(arg0, arg1, arg2, ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequeueActiveTasksOfWorker mocks base method.
|
// RequeueActiveTasksOfWorker mocks base method.
|
||||||
func (m *MockTaskStateMachine) RequeueActiveTasksOfWorker(arg0 context.Context, arg1 *persistence.Worker, arg2 string) error {
|
func (m *MockTaskStateMachine) RequeueActiveTasksOfWorker(arg0 context.Context, arg1 *sqlc.Worker, arg2 string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "RequeueActiveTasksOfWorker", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "RequeueActiveTasksOfWorker", arg0, arg1, arg2)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -1031,7 +1046,7 @@ func (mr *MockTaskStateMachineMockRecorder) RequeueActiveTasksOfWorker(arg0, arg
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequeueFailedTasksOfWorkerOfJob mocks base method.
|
// RequeueFailedTasksOfWorkerOfJob mocks base method.
|
||||||
func (m *MockTaskStateMachine) RequeueFailedTasksOfWorkerOfJob(arg0 context.Context, arg1 *persistence.Worker, arg2 *persistence.Job, arg3 string) error {
|
func (m *MockTaskStateMachine) RequeueFailedTasksOfWorkerOfJob(arg0 context.Context, arg1 *sqlc.Worker, arg2 *persistence.Job, arg3 string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "RequeueFailedTasksOfWorkerOfJob", arg0, arg1, arg2, arg3)
|
ret := m.ctrl.Call(m, "RequeueFailedTasksOfWorkerOfJob", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
|
@ -236,7 +236,7 @@ func assertResponseNoBody(t *testing.T, echoCtx echo.Context, expectStatus int)
|
|||||||
|
|
||||||
func testWorker() persistence.Worker {
|
func testWorker() persistence.Worker {
|
||||||
return persistence.Worker{
|
return persistence.Worker{
|
||||||
Model: persistence.Model{ID: 1},
|
ID: 1,
|
||||||
UUID: "e7632d62-c3b8-4af0-9e78-01752928952c",
|
UUID: "e7632d62-c3b8-4af0-9e78-01752928952c",
|
||||||
Name: "дрон",
|
Name: "дрон",
|
||||||
Address: "fe80::5054:ff:fede:2ad7",
|
Address: "fe80::5054:ff:fede:2ad7",
|
||||||
|
@ -57,6 +57,15 @@ func (f *Flamenco) FetchWorker(e echo.Context, workerUUID string) error {
|
|||||||
return sendAPIError(e, http.StatusInternalServerError, "error fetching worker: %v", err)
|
return sendAPIError(e, http.StatusInternalServerError, "error fetching worker: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
workerTags, err := f.persist.FetchTagsOfWorker(ctx, workerUUID)
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, context.Canceled):
|
||||||
|
return handleConnectionClosed(e, logger, "fetching worker tags")
|
||||||
|
case err != nil:
|
||||||
|
logger.Error().AnErr("cause", err).Msg("fetching worker tags")
|
||||||
|
return sendAPIError(e, http.StatusInternalServerError, "error fetching worker tags: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
dbTask, err := f.persist.FetchWorkerTask(ctx, dbWorker)
|
dbTask, err := f.persist.FetchWorkerTask(ctx, dbWorker)
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, context.Canceled):
|
case errors.Is(err, context.Canceled):
|
||||||
@ -77,6 +86,20 @@ func (f *Flamenco) FetchWorker(e echo.Context, workerUUID string) error {
|
|||||||
apiWorker.Task = &apiWorkerTask
|
apiWorker.Task = &apiWorkerTask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: see which API calls actually need the worker tags, and whether it's
|
||||||
|
// better to just call a specific API operation in those cases.
|
||||||
|
if len(workerTags) > 0 {
|
||||||
|
apiTags := make([]api.WorkerTag, len(workerTags))
|
||||||
|
for index, tag := range workerTags {
|
||||||
|
apiTags[index].Id = &tag.UUID
|
||||||
|
apiTags[index].Name = tag.Name
|
||||||
|
if tag.Description != "" {
|
||||||
|
apiTags[index].Description = &tag.Description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apiWorker.Tags = &apiTags
|
||||||
|
}
|
||||||
|
|
||||||
return e.JSON(http.StatusOK, apiWorker)
|
return e.JSON(http.StatusOK, apiWorker)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,8 +487,8 @@ func workerSummary(w persistence.Worker) api.WorkerSummary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !w.LastSeenAt.IsZero() {
|
if w.LastSeenAt.Valid {
|
||||||
summary.LastSeen = &w.LastSeenAt
|
summary.LastSeen = &w.LastSeenAt.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
return summary
|
return summary
|
||||||
@ -478,15 +501,6 @@ func workerDBtoAPI(w persistence.Worker) api.Worker {
|
|||||||
Platform: w.Platform,
|
Platform: w.Platform,
|
||||||
SupportedTaskTypes: w.TaskTypes(),
|
SupportedTaskTypes: w.TaskTypes(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(w.Tags) > 0 {
|
|
||||||
tags := []api.WorkerTag{}
|
|
||||||
for i := range w.Tags {
|
|
||||||
tags = append(tags, *workerTagDBtoAPI(w.Tags[i]))
|
|
||||||
}
|
|
||||||
apiWorker.Tags = &tags
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiWorker
|
return apiWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +85,15 @@ func TestFetchWorker(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertResponseAPIError(t, echo, http.StatusInternalServerError, "error fetching worker: some unknown error")
|
assertResponseAPIError(t, echo, http.StatusInternalServerError, "error fetching worker: some unknown error")
|
||||||
|
|
||||||
|
// Test database error fetching worker tags.
|
||||||
|
mf.persistence.EXPECT().FetchWorker(gomock.Any(), workerUUID).Return(&worker, nil)
|
||||||
|
mf.persistence.EXPECT().FetchTagsOfWorker(gomock.Any(), workerUUID).
|
||||||
|
Return(nil, errors.New("some tag fetching error"))
|
||||||
|
echo = mf.prepareMockedRequest(nil)
|
||||||
|
err = mf.flamenco.FetchWorker(echo, workerUUID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertResponseAPIError(t, echo, http.StatusInternalServerError, "error fetching worker tags: some tag fetching error")
|
||||||
|
|
||||||
// Test with worker that does NOT have a status change requested, and DOES have an assigned task.
|
// Test with worker that does NOT have a status change requested, and DOES have an assigned task.
|
||||||
mf.persistence.EXPECT().FetchWorker(gomock.Any(), workerUUID).Return(&worker, nil)
|
mf.persistence.EXPECT().FetchWorker(gomock.Any(), workerUUID).Return(&worker, nil)
|
||||||
assignedTask := persistence.Task{
|
assignedTask := persistence.Task{
|
||||||
@ -93,6 +102,10 @@ func TestFetchWorker(t *testing.T) {
|
|||||||
Job: &persistence.Job{UUID: "f0e25ee4-0d13-4291-afc3-e9446b555aaf"},
|
Job: &persistence.Job{UUID: "f0e25ee4-0d13-4291-afc3-e9446b555aaf"},
|
||||||
Status: api.TaskStatusActive,
|
Status: api.TaskStatusActive,
|
||||||
}
|
}
|
||||||
|
mf.persistence.EXPECT().FetchTagsOfWorker(gomock.Any(), workerUUID).Return([]persistence.WorkerTag{
|
||||||
|
{UUID: "0e701402-c4cc-49b0-8b8c-3eb8718d463a", Name: "EEVEE"},
|
||||||
|
{UUID: "59211f0a-81cc-4148-b0b7-32b3e2dcdb8f", Name: "Cycles"},
|
||||||
|
}, nil)
|
||||||
mf.persistence.EXPECT().FetchWorkerTask(gomock.Any(), &worker).Return(&assignedTask, nil)
|
mf.persistence.EXPECT().FetchWorkerTask(gomock.Any(), &worker).Return(&assignedTask, nil)
|
||||||
|
|
||||||
echo = mf.prepareMockedRequest(nil)
|
echo = mf.prepareMockedRequest(nil)
|
||||||
@ -116,12 +129,17 @@ func TestFetchWorker(t *testing.T) {
|
|||||||
},
|
},
|
||||||
JobId: assignedTask.Job.UUID,
|
JobId: assignedTask.Job.UUID,
|
||||||
},
|
},
|
||||||
|
Tags: &[]api.WorkerTag{
|
||||||
|
{Id: ptr("0e701402-c4cc-49b0-8b8c-3eb8718d463a"), Name: "EEVEE"},
|
||||||
|
{Id: ptr("59211f0a-81cc-4148-b0b7-32b3e2dcdb8f"), Name: "Cycles"},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test with worker that does have a status change requested, but does NOT Have an assigned task.
|
// Test with worker that does have a status change requested, but does NOT Have an assigned task.
|
||||||
requestedStatus := api.WorkerStatusAsleep
|
requestedStatus := api.WorkerStatusAsleep
|
||||||
worker.StatusChangeRequest(requestedStatus, false)
|
worker.StatusChangeRequest(requestedStatus, false)
|
||||||
mf.persistence.EXPECT().FetchWorker(gomock.Any(), workerUUID).Return(&worker, nil)
|
mf.persistence.EXPECT().FetchWorker(gomock.Any(), workerUUID).Return(&worker, nil)
|
||||||
|
mf.persistence.EXPECT().FetchTagsOfWorker(gomock.Any(), workerUUID).Return([]persistence.WorkerTag{}, nil)
|
||||||
mf.persistence.EXPECT().FetchWorkerTask(gomock.Any(), &worker).Return(nil, nil)
|
mf.persistence.EXPECT().FetchWorkerTask(gomock.Any(), &worker).Return(nil, nil)
|
||||||
|
|
||||||
echo = mf.prepareMockedRequest(nil)
|
echo = mf.prepareMockedRequest(nil)
|
||||||
@ -170,7 +188,7 @@ func TestDeleteWorker(t *testing.T) {
|
|||||||
Id: worker.UUID,
|
Id: worker.UUID,
|
||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
Status: worker.Status,
|
Status: worker.Status,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -201,7 +219,7 @@ func TestRequestWorkerStatusChange(t *testing.T) {
|
|||||||
Id: worker.UUID,
|
Id: worker.UUID,
|
||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
Status: prevStatus,
|
Status: prevStatus,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
StatusChange: &api.WorkerStatusChangeRequest{
|
StatusChange: &api.WorkerStatusChangeRequest{
|
||||||
Status: requestStatus,
|
Status: requestStatus,
|
||||||
@ -245,7 +263,7 @@ func TestRequestWorkerStatusChangeRevert(t *testing.T) {
|
|||||||
Id: worker.UUID,
|
Id: worker.UUID,
|
||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
Status: currentStatus,
|
Status: currentStatus,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
StatusChange: nil,
|
StatusChange: nil,
|
||||||
})
|
})
|
||||||
|
@ -52,7 +52,7 @@ func (f *Flamenco) TaskUpdate(e echo.Context, taskID string) error {
|
|||||||
Msg("worker trying to update task that's not assigned to any worker")
|
Msg("worker trying to update task that's not assigned to any worker")
|
||||||
return sendAPIError(e, http.StatusConflict, "task %+v is not assigned to any worker, so also not to you", taskID)
|
return sendAPIError(e, http.StatusConflict, "task %+v is not assigned to any worker, so also not to you", taskID)
|
||||||
}
|
}
|
||||||
if *dbTask.WorkerID != worker.ID {
|
if *dbTask.WorkerID != uint(worker.ID) {
|
||||||
logger.Warn().Msg("worker trying to update task that's assigned to another worker")
|
logger.Warn().Msg("worker trying to update task that's assigned to another worker")
|
||||||
return sendAPIError(e, http.StatusConflict, "task %+v is not assigned to you", taskID)
|
return sendAPIError(e, http.StatusConflict, "task %+v is not assigned to you", taskID)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func TestTaskUpdate(t *testing.T) {
|
|||||||
mockTask := persistence.Task{
|
mockTask := persistence.Task{
|
||||||
UUID: taskID,
|
UUID: taskID,
|
||||||
Worker: &worker,
|
Worker: &worker,
|
||||||
WorkerID: &worker.ID,
|
WorkerID: ptr(uint(worker.ID)),
|
||||||
Job: &mockJob,
|
Job: &mockJob,
|
||||||
Activity: "pre-update activity",
|
Activity: "pre-update activity",
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ func TestTaskUpdateFailed(t *testing.T) {
|
|||||||
mockTask := persistence.Task{
|
mockTask := persistence.Task{
|
||||||
UUID: taskID,
|
UUID: taskID,
|
||||||
Worker: &worker,
|
Worker: &worker,
|
||||||
WorkerID: &worker.ID,
|
WorkerID: ptr(uint(worker.ID)),
|
||||||
Job: &mockJob,
|
Job: &mockJob,
|
||||||
Activity: "pre-update activity",
|
Activity: "pre-update activity",
|
||||||
Type: "misc",
|
Type: "misc",
|
||||||
@ -189,7 +189,7 @@ func TestBlockingAfterFailure(t *testing.T) {
|
|||||||
mockTask := persistence.Task{
|
mockTask := persistence.Task{
|
||||||
UUID: taskID,
|
UUID: taskID,
|
||||||
Worker: &worker,
|
Worker: &worker,
|
||||||
WorkerID: &worker.ID,
|
WorkerID: ptr(uint(worker.ID)),
|
||||||
Job: &mockJob,
|
Job: &mockJob,
|
||||||
Activity: "pre-update activity",
|
Activity: "pre-update activity",
|
||||||
Type: "misc",
|
Type: "misc",
|
||||||
@ -339,7 +339,7 @@ func TestJobFailureAfterWorkerTaskFailure(t *testing.T) {
|
|||||||
mockTask := persistence.Task{
|
mockTask := persistence.Task{
|
||||||
UUID: taskID,
|
UUID: taskID,
|
||||||
Worker: &worker,
|
Worker: &worker,
|
||||||
WorkerID: &worker.ID,
|
WorkerID: ptr(uint(worker.ID)),
|
||||||
Job: &mockJob,
|
Job: &mockJob,
|
||||||
Activity: "pre-update activity",
|
Activity: "pre-update activity",
|
||||||
Type: "misc",
|
Type: "misc",
|
||||||
|
@ -582,7 +582,7 @@ func mayWorkerRun(worker *persistence.Worker, dbTask *persistence.Task) api.MayK
|
|||||||
StatusChangeRequested: true,
|
StatusChangeRequested: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dbTask.WorkerID == nil || *dbTask.WorkerID != worker.ID {
|
if dbTask.WorkerID == nil || *dbTask.WorkerID != uint(worker.ID) {
|
||||||
return api.MayKeepRunning{Reason: "task not assigned to this worker"}
|
return api.MayKeepRunning{Reason: "task not assigned to this worker"}
|
||||||
}
|
}
|
||||||
if !task_state_machine.IsRunnableTaskStatus(dbTask.Status) {
|
if !task_state_machine.IsRunnableTaskStatus(dbTask.Status) {
|
||||||
|
@ -193,7 +193,7 @@ func TestWorkerSignOn(t *testing.T) {
|
|||||||
Name: "Lazy Boi",
|
Name: "Lazy Boi",
|
||||||
PreviousStatus: &prevStatus,
|
PreviousStatus: &prevStatus,
|
||||||
Status: api.WorkerStatusStarting,
|
Status: api.WorkerStatusStarting,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: "3.0-testing",
|
Version: "3.0-testing",
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ func TestWorkerSignoffTaskRequeue(t *testing.T) {
|
|||||||
IsLazy: false,
|
IsLazy: false,
|
||||||
Status: api.WorkerStatusAwake,
|
Status: api.WorkerStatusAwake,
|
||||||
},
|
},
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ func TestWorkerRememberPreviousStatus(t *testing.T) {
|
|||||||
IsLazy: false,
|
IsLazy: false,
|
||||||
Status: api.WorkerStatusAwake,
|
Status: api.WorkerStatusAwake,
|
||||||
},
|
},
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -316,7 +316,7 @@ func TestWorkerDontRememberPreviousStatus(t *testing.T) {
|
|||||||
PreviousStatus: ptr(api.WorkerStatusError),
|
PreviousStatus: ptr(api.WorkerStatusError),
|
||||||
Status: api.WorkerStatusOffline,
|
Status: api.WorkerStatusOffline,
|
||||||
StatusChange: nil,
|
StatusChange: nil,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ func TestWorkerStateChanged(t *testing.T) {
|
|||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
PreviousStatus: &prevStatus,
|
PreviousStatus: &prevStatus,
|
||||||
Status: api.WorkerStatusAsleep,
|
Status: api.WorkerStatusAsleep,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -423,7 +423,7 @@ func TestWorkerStateChangedAfterChangeRequest(t *testing.T) {
|
|||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
PreviousStatus: ptr(api.WorkerStatusOffline),
|
PreviousStatus: ptr(api.WorkerStatusOffline),
|
||||||
Status: api.WorkerStatusStarting,
|
Status: api.WorkerStatusStarting,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
StatusChange: &api.WorkerStatusChangeRequest{
|
StatusChange: &api.WorkerStatusChangeRequest{
|
||||||
Status: api.WorkerStatusAsleep,
|
Status: api.WorkerStatusAsleep,
|
||||||
@ -456,7 +456,7 @@ func TestWorkerStateChangedAfterChangeRequest(t *testing.T) {
|
|||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
PreviousStatus: ptr(api.WorkerStatusStarting),
|
PreviousStatus: ptr(api.WorkerStatusStarting),
|
||||||
Status: api.WorkerStatusAsleep,
|
Status: api.WorkerStatusAsleep,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -526,7 +526,7 @@ func TestMayWorkerRun(t *testing.T) {
|
|||||||
mf.persistence.EXPECT().TaskTouchedByWorker(gomock.Any(), &task).Return(nil)
|
mf.persistence.EXPECT().TaskTouchedByWorker(gomock.Any(), &task).Return(nil)
|
||||||
|
|
||||||
echo := prepareRequest()
|
echo := prepareRequest()
|
||||||
task.WorkerID = &worker.ID
|
task.WorkerID = ptr(uint(worker.ID))
|
||||||
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertResponseJSON(t, echo, http.StatusOK, api.MayKeepRunning{
|
assertResponseJSON(t, echo, http.StatusOK, api.MayKeepRunning{
|
||||||
@ -537,7 +537,7 @@ func TestMayWorkerRun(t *testing.T) {
|
|||||||
// Test: unhappy, assigned but cancelled.
|
// Test: unhappy, assigned but cancelled.
|
||||||
{
|
{
|
||||||
echo := prepareRequest()
|
echo := prepareRequest()
|
||||||
task.WorkerID = &worker.ID
|
task.WorkerID = ptr(uint(worker.ID))
|
||||||
task.Status = api.TaskStatusCanceled
|
task.Status = api.TaskStatusCanceled
|
||||||
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -551,7 +551,7 @@ func TestMayWorkerRun(t *testing.T) {
|
|||||||
{
|
{
|
||||||
worker.StatusChangeRequest(api.WorkerStatusAsleep, false)
|
worker.StatusChangeRequest(api.WorkerStatusAsleep, false)
|
||||||
echo := prepareRequest()
|
echo := prepareRequest()
|
||||||
task.WorkerID = &worker.ID
|
task.WorkerID = ptr(uint(worker.ID))
|
||||||
task.Status = api.TaskStatusActive
|
task.Status = api.TaskStatusActive
|
||||||
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -569,7 +569,7 @@ func TestMayWorkerRun(t *testing.T) {
|
|||||||
|
|
||||||
worker.StatusChangeRequest(api.WorkerStatusAsleep, true)
|
worker.StatusChangeRequest(api.WorkerStatusAsleep, true)
|
||||||
echo := prepareRequest()
|
echo := prepareRequest()
|
||||||
task.WorkerID = &worker.ID
|
task.WorkerID = ptr(uint(worker.ID))
|
||||||
task.Status = api.TaskStatusActive
|
task.Status = api.TaskStatusActive
|
||||||
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
err := mf.flamenco.MayWorkerRun(echo, task.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -18,7 +18,7 @@ func NewWorkerUpdate(worker *persistence.Worker) api.EventWorkerUpdate {
|
|||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
Status: worker.Status,
|
Status: worker.Status,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
CanRestart: worker.CanRestart,
|
CanRestart: worker.CanRestart,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,8 +29,8 @@ func NewWorkerUpdate(worker *persistence.Worker) api.EventWorkerUpdate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !worker.LastSeenAt.IsZero() {
|
if worker.LastSeenAt.Valid {
|
||||||
workerUpdate.LastSeen = &worker.LastSeenAt
|
workerUpdate.LastSeen = &worker.LastSeenAt.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add tag IDs.
|
// TODO: add tag IDs.
|
||||||
|
16
internal/manager/persistence/conversion.go
Normal file
16
internal/manager/persistence/conversion.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package persistence
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import "database/sql"
|
||||||
|
|
||||||
|
func nullTimeToUTC(t sql.NullTime) sql.NullTime {
|
||||||
|
return sql.NullTime{
|
||||||
|
Time: t.Time.UTC(),
|
||||||
|
Valid: t.Valid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptr[T any](value T) *T {
|
||||||
|
return &value
|
||||||
|
}
|
44
internal/manager/persistence/conversion_test.go
Normal file
44
internal/manager/persistence/conversion_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package persistence
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_nullTimeToUTC(t *testing.T) {
|
||||||
|
|
||||||
|
inUTC := mustParseTime("2024-11-11T20:12:47Z")
|
||||||
|
inBangkok := mustParseTime("2024-11-12T03:12:47+07:00")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
arg sql.NullTime
|
||||||
|
want sql.NullTime
|
||||||
|
}{
|
||||||
|
{"zero", sql.NullTime{}, sql.NullTime{}},
|
||||||
|
{"invalid-nonzero-utc",
|
||||||
|
sql.NullTime{Time: inUTC, Valid: false},
|
||||||
|
sql.NullTime{Time: inUTC, Valid: false},
|
||||||
|
},
|
||||||
|
{"valid-nonzero-utc",
|
||||||
|
sql.NullTime{Time: inUTC, Valid: true},
|
||||||
|
sql.NullTime{Time: inUTC, Valid: true},
|
||||||
|
},
|
||||||
|
{"invalid-nonzero-bangkok",
|
||||||
|
sql.NullTime{Time: inBangkok, Valid: false},
|
||||||
|
sql.NullTime{Time: inUTC, Valid: false},
|
||||||
|
},
|
||||||
|
{"valid-nonzero-bangkok",
|
||||||
|
sql.NullTime{Time: inBangkok, Valid: true},
|
||||||
|
sql.NullTime{Time: inUTC, Valid: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := nullTimeToUTC(tt.arg); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("nullTimeToUTC() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -37,19 +37,19 @@ func (e PersistenceError) Is(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func jobError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
func jobError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
||||||
return wrapError(translateGormJobError(errorToWrap), message, msgArgs...)
|
return wrapError(translateJobError(errorToWrap), message, msgArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func taskError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
func taskError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
||||||
return wrapError(translateGormTaskError(errorToWrap), message, msgArgs...)
|
return wrapError(translateTaskError(errorToWrap), message, msgArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func workerError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
func workerError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
||||||
return wrapError(translateGormWorkerError(errorToWrap), message, msgArgs...)
|
return wrapError(translateWorkerError(errorToWrap), message, msgArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func workerTagError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
func workerTagError(errorToWrap error, message string, msgArgs ...interface{}) error {
|
||||||
return wrapError(translateGormWorkerTagError(errorToWrap), message, msgArgs...)
|
return wrapError(translateWorkerTagError(errorToWrap), message, msgArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapError(errorToWrap error, message string, format ...interface{}) error {
|
func wrapError(errorToWrap error, message string, format ...interface{}) error {
|
||||||
@ -73,36 +73,36 @@ func wrapError(errorToWrap error, message string, format ...interface{}) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// translateGormJobError translates a Gorm error to a persistence layer error.
|
// translateJobError translates a Gorm error to a persistence layer error.
|
||||||
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
||||||
func translateGormJobError(err error) error {
|
func translateJobError(err error) error {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return ErrJobNotFound
|
return ErrJobNotFound
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// translateGormTaskError translates a Gorm error to a persistence layer error.
|
// translateTaskError translates a Gorm error to a persistence layer error.
|
||||||
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
||||||
func translateGormTaskError(err error) error {
|
func translateTaskError(err error) error {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return ErrTaskNotFound
|
return ErrTaskNotFound
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// translateGormWorkerError translates a Gorm error to a persistence layer error.
|
// translateWorkerError translates a Gorm error to a persistence layer error.
|
||||||
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
||||||
func translateGormWorkerError(err error) error {
|
func translateWorkerError(err error) error {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return ErrWorkerNotFound
|
return ErrWorkerNotFound
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// translateGormWorkerTagError translates a Gorm error to a persistence layer error.
|
// translateWorkerTagError translates a Gorm error to a persistence layer error.
|
||||||
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
// This helps to keep Gorm as "implementation detail" of the persistence layer.
|
||||||
func translateGormWorkerTagError(err error) error {
|
func translateWorkerTagError(err error) error {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return ErrWorkerTagNotFound
|
return ErrWorkerTagNotFound
|
||||||
}
|
}
|
||||||
|
@ -17,18 +17,18 @@ func TestNotFoundErrors(t *testing.T) {
|
|||||||
assert.Contains(t, ErrTaskNotFound.Error(), "task")
|
assert.Contains(t, ErrTaskNotFound.Error(), "task")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTranslateGormJobError(t *testing.T) {
|
func TestTranslateJobError(t *testing.T) {
|
||||||
assert.Nil(t, translateGormJobError(nil))
|
assert.Nil(t, translateJobError(nil))
|
||||||
assert.Equal(t, ErrJobNotFound, translateGormJobError(sql.ErrNoRows))
|
assert.Equal(t, ErrJobNotFound, translateJobError(sql.ErrNoRows))
|
||||||
|
|
||||||
otherError := errors.New("this error is not special for this function")
|
otherError := errors.New("this error is not special for this function")
|
||||||
assert.Equal(t, otherError, translateGormJobError(otherError))
|
assert.Equal(t, otherError, translateJobError(otherError))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTranslateGormTaskError(t *testing.T) {
|
func TestTranslateTaskError(t *testing.T) {
|
||||||
assert.Nil(t, translateGormTaskError(nil))
|
assert.Nil(t, translateTaskError(nil))
|
||||||
assert.Equal(t, ErrTaskNotFound, translateGormTaskError(sql.ErrNoRows))
|
assert.Equal(t, ErrTaskNotFound, translateTaskError(sql.ErrNoRows))
|
||||||
|
|
||||||
otherError := errors.New("this error is not special for this function")
|
otherError := errors.New("this error is not special for this function")
|
||||||
assert.Equal(t, otherError, translateGormTaskError(otherError))
|
assert.Equal(t, otherError, translateTaskError(otherError))
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ func (db *DB) StoreAuthoredJob(ctx context.Context, authoredJob job_compilers.Au
|
|||||||
Name: authoredJob.Name,
|
Name: authoredJob.Name,
|
||||||
JobType: authoredJob.JobType,
|
JobType: authoredJob.JobType,
|
||||||
Priority: int64(authoredJob.Priority),
|
Priority: int64(authoredJob.Priority),
|
||||||
Status: string(authoredJob.Status),
|
Status: authoredJob.Status,
|
||||||
Settings: settings,
|
Settings: settings,
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
StorageShamanCheckoutID: authoredJob.Storage.ShamanCheckoutID,
|
StorageShamanCheckoutID: authoredJob.Storage.ShamanCheckoutID,
|
||||||
@ -182,7 +182,7 @@ func (db *DB) StoreAuthoredJob(ctx context.Context, authoredJob job_compilers.Au
|
|||||||
Str("job", params.UUID).
|
Str("job", params.UUID).
|
||||||
Str("type", params.JobType).
|
Str("type", params.JobType).
|
||||||
Str("name", params.Name).
|
Str("name", params.Name).
|
||||||
Str("status", params.Status).
|
Str("status", string(params.Status)).
|
||||||
Msg("persistence: storing authored job")
|
Msg("persistence: storing authored job")
|
||||||
|
|
||||||
jobID, err := qtx.queries.CreateJob(ctx, params)
|
jobID, err := qtx.queries.CreateJob(ctx, params)
|
||||||
@ -261,7 +261,7 @@ func (db *DB) storeAuthoredJobTaks(
|
|||||||
JobID: jobID,
|
JobID: jobID,
|
||||||
IndexInJob: int64(taskIndex + 1), // indexInJob is base-1.
|
IndexInJob: int64(taskIndex + 1), // indexInJob is base-1.
|
||||||
Priority: int64(authoredTask.Priority),
|
Priority: int64(authoredTask.Priority),
|
||||||
Status: string(api.TaskStatusQueued),
|
Status: api.TaskStatusQueued,
|
||||||
Commands: commandsJSON,
|
Commands: commandsJSON,
|
||||||
// dependencies are stored below.
|
// dependencies are stored below.
|
||||||
}
|
}
|
||||||
@ -492,12 +492,7 @@ func (db *DB) FetchJobsDeletionRequested(ctx context.Context) ([]string, error)
|
|||||||
func (db *DB) FetchJobsInStatus(ctx context.Context, jobStatuses ...api.JobStatus) ([]*Job, error) {
|
func (db *DB) FetchJobsInStatus(ctx context.Context, jobStatuses ...api.JobStatus) ([]*Job, error) {
|
||||||
queries := db.queries()
|
queries := db.queries()
|
||||||
|
|
||||||
statuses := []string{}
|
sqlcJobs, err := queries.FetchJobsInStatus(ctx, jobStatuses)
|
||||||
for _, status := range jobStatuses {
|
|
||||||
statuses = append(statuses, string(status))
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlcJobs, err := queries.FetchJobsInStatus(ctx, statuses)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, jobError(err, "fetching jobs in status %q", jobStatuses)
|
return nil, jobError(err, "fetching jobs in status %q", jobStatuses)
|
||||||
}
|
}
|
||||||
@ -521,7 +516,7 @@ func (db *DB) SaveJobStatus(ctx context.Context, j *Job) error {
|
|||||||
params := sqlc.SaveJobStatusParams{
|
params := sqlc.SaveJobStatusParams{
|
||||||
Now: db.nowNullable(),
|
Now: db.nowNullable(),
|
||||||
ID: int64(j.ID),
|
ID: int64(j.ID),
|
||||||
Status: string(j.Status),
|
Status: j.Status,
|
||||||
Activity: j.Activity,
|
Activity: j.Activity,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,7 +582,8 @@ func convertSqlTaskWithJobAndWorker(
|
|||||||
) (*Task, error) {
|
) (*Task, error) {
|
||||||
var (
|
var (
|
||||||
gormJob Job
|
gormJob Job
|
||||||
gormWorker Worker
|
worker Worker
|
||||||
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fetch & convert the Job.
|
// Fetch & convert the Job.
|
||||||
@ -603,17 +599,16 @@ func convertSqlTaskWithJobAndWorker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch & convert the Worker.
|
// Fetch the Worker.
|
||||||
if task.WorkerID.Valid && task.WorkerID.Int64 > 0 {
|
if task.WorkerID.Valid && task.WorkerID.Int64 > 0 {
|
||||||
sqlcWorker, err := queries.FetchWorkerUnconditionalByID(ctx, task.WorkerID.Int64)
|
worker, err = queries.FetchWorkerUnconditionalByID(ctx, task.WorkerID.Int64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, taskError(err, "fetching worker assigned to task %s", task.UUID)
|
return nil, taskError(err, "fetching worker assigned to task %s", task.UUID)
|
||||||
}
|
}
|
||||||
gormWorker = *convertSqlcWorker(sqlcWorker)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the Task.
|
// Convert the Task.
|
||||||
gormTask, err := convertSqlcTask(task, gormJob.UUID, gormWorker.UUID)
|
gormTask, err := convertSqlcTask(task, gormJob.UUID, worker.UUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -623,9 +618,9 @@ func convertSqlTaskWithJobAndWorker(
|
|||||||
gormTask.Job = &gormJob
|
gormTask.Job = &gormJob
|
||||||
gormTask.JobUUID = gormJob.UUID
|
gormTask.JobUUID = gormJob.UUID
|
||||||
}
|
}
|
||||||
if gormWorker.ID > 0 {
|
if worker.ID > 0 {
|
||||||
gormTask.Worker = &gormWorker
|
gormTask.Worker = &worker
|
||||||
gormTask.WorkerUUID = gormWorker.UUID
|
gormTask.WorkerUUID = worker.UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
return gormTask, nil
|
return gormTask, nil
|
||||||
@ -664,7 +659,7 @@ func (db *DB) SaveTask(ctx context.Context, t *Task) error {
|
|||||||
Name: t.Name,
|
Name: t.Name,
|
||||||
Type: t.Type,
|
Type: t.Type,
|
||||||
Priority: int64(t.Priority),
|
Priority: int64(t.Priority),
|
||||||
Status: string(t.Status),
|
Status: t.Status,
|
||||||
Commands: commandsJSON,
|
Commands: commandsJSON,
|
||||||
Activity: t.Activity,
|
Activity: t.Activity,
|
||||||
ID: int64(t.ID),
|
ID: int64(t.ID),
|
||||||
@ -700,7 +695,7 @@ func (db *DB) SaveTaskStatus(ctx context.Context, t *Task) error {
|
|||||||
|
|
||||||
err := queries.UpdateTaskStatus(ctx, sqlc.UpdateTaskStatusParams{
|
err := queries.UpdateTaskStatus(ctx, sqlc.UpdateTaskStatusParams{
|
||||||
UpdatedAt: db.nowNullable(),
|
UpdatedAt: db.nowNullable(),
|
||||||
Status: string(t.Status),
|
Status: t.Status,
|
||||||
ID: int64(t.ID),
|
ID: int64(t.ID),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -743,7 +738,7 @@ func (db *DB) TaskAssignToWorker(ctx context.Context, t *Task, w *Worker) error
|
|||||||
|
|
||||||
// Update the task itself.
|
// Update the task itself.
|
||||||
t.Worker = w
|
t.Worker = w
|
||||||
t.WorkerID = &w.ID
|
t.WorkerID = ptr(uint(w.ID))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -756,7 +751,7 @@ func (db *DB) FetchTasksOfWorkerInStatus(ctx context.Context, worker *Worker, ta
|
|||||||
Int64: int64(worker.ID),
|
Int64: int64(worker.ID),
|
||||||
Valid: true,
|
Valid: true,
|
||||||
},
|
},
|
||||||
TaskStatus: string(taskStatus),
|
TaskStatus: taskStatus,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, taskError(err, "finding tasks of worker %s in status %q", worker.UUID, taskStatus)
|
return nil, taskError(err, "finding tasks of worker %s in status %q", worker.UUID, taskStatus)
|
||||||
@ -772,7 +767,7 @@ func (db *DB) FetchTasksOfWorkerInStatus(ctx context.Context, worker *Worker, ta
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
gormTask.Worker = worker
|
gormTask.Worker = worker
|
||||||
gormTask.WorkerID = &worker.ID
|
gormTask.WorkerID = ptr(uint(worker.ID))
|
||||||
|
|
||||||
// Fetch the job, either from the cache or from the database. This is done
|
// Fetch the job, either from the cache or from the database. This is done
|
||||||
// here because the task_state_machine functionality expects that task.Job
|
// here because the task_state_machine functionality expects that task.Job
|
||||||
@ -802,7 +797,7 @@ func (db *DB) FetchTasksOfWorkerInStatusOfJob(ctx context.Context, worker *Worke
|
|||||||
Valid: true,
|
Valid: true,
|
||||||
},
|
},
|
||||||
JobID: int64(job.ID),
|
JobID: int64(job.ID),
|
||||||
TaskStatus: string(taskStatus),
|
TaskStatus: taskStatus,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, taskError(err, "finding tasks of worker %s in status %q and job %s", worker.UUID, taskStatus, job.UUID)
|
return nil, taskError(err, "finding tasks of worker %s in status %q and job %s", worker.UUID, taskStatus, job.UUID)
|
||||||
@ -817,7 +812,7 @@ func (db *DB) FetchTasksOfWorkerInStatusOfJob(ctx context.Context, worker *Worke
|
|||||||
gormTask.Job = job
|
gormTask.Job = job
|
||||||
gormTask.JobID = job.ID
|
gormTask.JobID = job.ID
|
||||||
gormTask.Worker = worker
|
gormTask.Worker = worker
|
||||||
gormTask.WorkerID = &worker.ID
|
gormTask.WorkerID = ptr(uint(worker.ID))
|
||||||
result[i] = gormTask
|
result[i] = gormTask
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
@ -828,7 +823,7 @@ func (db *DB) JobHasTasksInStatus(ctx context.Context, job *Job, taskStatus api.
|
|||||||
|
|
||||||
count, err := queries.JobCountTasksInStatus(ctx, sqlc.JobCountTasksInStatusParams{
|
count, err := queries.JobCountTasksInStatus(ctx, sqlc.JobCountTasksInStatusParams{
|
||||||
JobID: int64(job.ID),
|
JobID: int64(job.ID),
|
||||||
TaskStatus: string(taskStatus),
|
TaskStatus: taskStatus,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, taskError(err, "counting tasks of job %s in status %q", job.UUID, taskStatus)
|
return false, taskError(err, "counting tasks of job %s in status %q", job.UUID, taskStatus)
|
||||||
@ -896,7 +891,7 @@ func (db *DB) FetchTasksOfJobInStatus(ctx context.Context, job *Job, taskStatuse
|
|||||||
|
|
||||||
rows, err := queries.FetchTasksOfJobInStatus(ctx, sqlc.FetchTasksOfJobInStatusParams{
|
rows, err := queries.FetchTasksOfJobInStatus(ctx, sqlc.FetchTasksOfJobInStatusParams{
|
||||||
JobID: int64(job.ID),
|
JobID: int64(job.ID),
|
||||||
TaskStatus: convertTaskStatuses(taskStatuses),
|
TaskStatus: taskStatuses,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, taskError(err, "fetching tasks of job %s in status %q", job.UUID, taskStatuses)
|
return nil, taskError(err, "fetching tasks of job %s in status %q", job.UUID, taskStatuses)
|
||||||
@ -926,7 +921,7 @@ func (db *DB) UpdateJobsTaskStatuses(ctx context.Context, job *Job,
|
|||||||
|
|
||||||
err := queries.UpdateJobsTaskStatuses(ctx, sqlc.UpdateJobsTaskStatusesParams{
|
err := queries.UpdateJobsTaskStatuses(ctx, sqlc.UpdateJobsTaskStatusesParams{
|
||||||
UpdatedAt: db.nowNullable(),
|
UpdatedAt: db.nowNullable(),
|
||||||
Status: string(taskStatus),
|
Status: taskStatus,
|
||||||
Activity: activity,
|
Activity: activity,
|
||||||
JobID: int64(job.ID),
|
JobID: int64(job.ID),
|
||||||
})
|
})
|
||||||
@ -950,10 +945,10 @@ func (db *DB) UpdateJobsTaskStatusesConditional(ctx context.Context, job *Job,
|
|||||||
|
|
||||||
err := queries.UpdateJobsTaskStatusesConditional(ctx, sqlc.UpdateJobsTaskStatusesConditionalParams{
|
err := queries.UpdateJobsTaskStatusesConditional(ctx, sqlc.UpdateJobsTaskStatusesConditionalParams{
|
||||||
UpdatedAt: db.nowNullable(),
|
UpdatedAt: db.nowNullable(),
|
||||||
Status: string(taskStatus),
|
Status: taskStatus,
|
||||||
Activity: activity,
|
Activity: activity,
|
||||||
JobID: int64(job.ID),
|
JobID: int64(job.ID),
|
||||||
StatusesToUpdate: convertTaskStatuses(statusesToUpdate),
|
StatusesToUpdate: statusesToUpdate,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1041,7 +1036,7 @@ func (db *DB) FetchTaskFailureList(ctx context.Context, t *Task) ([]*Worker, err
|
|||||||
|
|
||||||
workers := make([]*Worker, len(failureList))
|
workers := make([]*Worker, len(failureList))
|
||||||
for idx := range failureList {
|
for idx := range failureList {
|
||||||
workers[idx] = convertSqlcWorker(failureList[idx].Worker)
|
workers[idx] = &failureList[idx].Worker
|
||||||
}
|
}
|
||||||
return workers, nil
|
return workers, nil
|
||||||
}
|
}
|
||||||
@ -1124,21 +1119,3 @@ func convertSqlcTask(task sqlc.Task, jobUUID string, workerUUID string) (*Task,
|
|||||||
|
|
||||||
return &dbTask, nil
|
return &dbTask, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertTaskStatuses converts from []api.TaskStatus to []string for feeding to sqlc.
|
|
||||||
func convertTaskStatuses(taskStatuses []api.TaskStatus) []string {
|
|
||||||
statusesAsStrings := make([]string, len(taskStatuses))
|
|
||||||
for index := range taskStatuses {
|
|
||||||
statusesAsStrings[index] = string(taskStatuses[index])
|
|
||||||
}
|
|
||||||
return statusesAsStrings
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertJobStatuses converts from []api.JobStatus to []string for feeding to sqlc.
|
|
||||||
func convertJobStatuses(jobStatuses []api.JobStatus) []string {
|
|
||||||
statusesAsStrings := make([]string, len(jobStatuses))
|
|
||||||
for index := range jobStatuses {
|
|
||||||
statusesAsStrings[index] = string(jobStatuses[index])
|
|
||||||
}
|
|
||||||
return statusesAsStrings
|
|
||||||
}
|
|
||||||
|
@ -119,7 +119,9 @@ func TestWorkersLeftToRun(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, left)
|
assert.Empty(t, left)
|
||||||
|
|
||||||
worker1 := createWorker(ctx, t, db)
|
worker1 := createWorker(ctx, t, db, func(w *Worker) {
|
||||||
|
w.UUID = "11111111-0000-1111-2222-333333333333"
|
||||||
|
})
|
||||||
worker2 := createWorkerFrom(ctx, t, db, *worker1)
|
worker2 := createWorkerFrom(ctx, t, db, *worker1)
|
||||||
|
|
||||||
// Create one worker tag. It will not be used by this job, but one of the
|
// Create one worker tag. It will not be used by this job, but one of the
|
||||||
@ -129,8 +131,8 @@ func TestWorkersLeftToRun(t *testing.T) {
|
|||||||
require.NoError(t, db.CreateWorkerTag(ctx, &tag1))
|
require.NoError(t, db.CreateWorkerTag(ctx, &tag1))
|
||||||
workerC1 := createWorker(ctx, t, db, func(w *Worker) {
|
workerC1 := createWorker(ctx, t, db, func(w *Worker) {
|
||||||
w.UUID = "c1c1c1c1-0000-1111-2222-333333333333"
|
w.UUID = "c1c1c1c1-0000-1111-2222-333333333333"
|
||||||
w.Tags = []*WorkerTag{&tag1}
|
|
||||||
})
|
})
|
||||||
|
require.NoError(t, db.WorkerSetTags(ctx, workerC1, []string{tag1.UUID}))
|
||||||
|
|
||||||
uuidMap := func(workers ...*Worker) map[string]bool {
|
uuidMap := func(workers ...*Worker) map[string]bool {
|
||||||
theMap := map[string]bool{}
|
theMap := map[string]bool{}
|
||||||
@ -185,23 +187,25 @@ func TestWorkersLeftToRunWithTags(t *testing.T) {
|
|||||||
// Tags 1 + 3
|
// Tags 1 + 3
|
||||||
workerC13 := createWorker(ctx, t, db, func(w *Worker) {
|
workerC13 := createWorker(ctx, t, db, func(w *Worker) {
|
||||||
w.UUID = "c13c1313-0000-1111-2222-333333333333"
|
w.UUID = "c13c1313-0000-1111-2222-333333333333"
|
||||||
w.Tags = []*WorkerTag{&tag1, &tag3}
|
|
||||||
})
|
})
|
||||||
|
require.NoError(t, db.WorkerSetTags(ctx, workerC13, []string{tag1.UUID, tag3.UUID}))
|
||||||
|
|
||||||
// Tag 1
|
// Tag 1
|
||||||
workerC1 := createWorker(ctx, t, db, func(w *Worker) {
|
workerC1 := createWorker(ctx, t, db, func(w *Worker) {
|
||||||
w.UUID = "c1c1c1c1-0000-1111-2222-333333333333"
|
w.UUID = "c1c1c1c1-0000-1111-2222-333333333333"
|
||||||
w.Tags = []*WorkerTag{&tag1}
|
|
||||||
})
|
})
|
||||||
|
require.NoError(t, db.WorkerSetTags(ctx, workerC1, []string{tag1.UUID}))
|
||||||
|
|
||||||
// Tag 2 worker, this one should never appear.
|
// Tag 2 worker, this one should never appear.
|
||||||
createWorker(ctx, t, db, func(w *Worker) {
|
workerC2 := createWorker(ctx, t, db, func(w *Worker) {
|
||||||
w.UUID = "c2c2c2c2-0000-1111-2222-333333333333"
|
w.UUID = "c2c2c2c2-0000-1111-2222-333333333333"
|
||||||
w.Tags = []*WorkerTag{&tag2}
|
|
||||||
})
|
})
|
||||||
|
require.NoError(t, db.WorkerSetTags(ctx, workerC2, []string{tag2.UUID}))
|
||||||
|
|
||||||
// No tags, so should be able to run only tagless jobs. Which is none
|
// No tags, so should be able to run only tagless jobs. Which is none
|
||||||
// in this test.
|
// in this test.
|
||||||
createWorker(ctx, t, db, func(w *Worker) {
|
createWorker(ctx, t, db, func(w *Worker) {
|
||||||
w.UUID = "00000000-0000-1111-2222-333333333333"
|
w.UUID = "00000000-0000-1111-2222-333333333333"
|
||||||
w.Tags = nil
|
|
||||||
})
|
})
|
||||||
|
|
||||||
uuidMap := func(workers ...*Worker) map[string]bool {
|
uuidMap := func(workers ...*Worker) map[string]bool {
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"projects.blender.org/studio/flamenco/internal/manager/job_compilers"
|
"projects.blender.org/studio/flamenco/internal/manager/job_compilers"
|
||||||
|
"projects.blender.org/studio/flamenco/internal/manager/persistence/sqlc"
|
||||||
"projects.blender.org/studio/flamenco/internal/uuid"
|
"projects.blender.org/studio/flamenco/internal/uuid"
|
||||||
"projects.blender.org/studio/flamenco/pkg/api"
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
@ -581,7 +582,7 @@ func TestTaskAssignToWorker(t *testing.T) {
|
|||||||
if task.WorkerID == nil {
|
if task.WorkerID == nil {
|
||||||
t.Error("task.WorkerID == nil")
|
t.Error("task.WorkerID == nil")
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(t, w.ID, *task.WorkerID)
|
assert.Equal(t, w.ID, int64(*task.WorkerID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,7 +714,7 @@ func TestAddWorkerToTaskFailedList(t *testing.T) {
|
|||||||
newWorker.ID = 0
|
newWorker.ID = 0
|
||||||
newWorker.UUID = "89ed2b02-b51b-4cd4-b44a-4a1c8d01db85"
|
newWorker.UUID = "89ed2b02-b51b-4cd4-b44a-4a1c8d01db85"
|
||||||
newWorker.Name = "Worker 2"
|
newWorker.Name = "Worker 2"
|
||||||
require.NoError(t, db.SaveWorker(ctx, &newWorker))
|
require.NoError(t, db.CreateWorker(ctx, &newWorker))
|
||||||
worker2, err := db.FetchWorker(ctx, newWorker.UUID)
|
worker2, err := db.FetchWorker(ctx, newWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -752,7 +753,7 @@ func TestClearFailureListOfTask(t *testing.T) {
|
|||||||
newWorker.ID = 0
|
newWorker.ID = 0
|
||||||
newWorker.UUID = "89ed2b02-b51b-4cd4-b44a-4a1c8d01db85"
|
newWorker.UUID = "89ed2b02-b51b-4cd4-b44a-4a1c8d01db85"
|
||||||
newWorker.Name = "Worker 2"
|
newWorker.Name = "Worker 2"
|
||||||
require.NoError(t, db.SaveWorker(ctx, &newWorker))
|
require.NoError(t, db.CreateWorker(ctx, &newWorker))
|
||||||
worker2, err := db.FetchWorker(ctx, newWorker.UUID)
|
worker2, err := db.FetchWorker(ctx, newWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -1020,7 +1021,6 @@ func createWorker(ctx context.Context, t *testing.T, db *DB, updaters ...func(*W
|
|||||||
Software: "3.0",
|
Software: "3.0",
|
||||||
Status: api.WorkerStatusAwake,
|
Status: api.WorkerStatusAwake,
|
||||||
SupportedTaskTypes: "blender,ffmpeg,file-management",
|
SupportedTaskTypes: "blender,ffmpeg,file-management",
|
||||||
Tags: nil,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, updater := range updaters {
|
for _, updater := range updaters {
|
||||||
@ -1039,14 +1039,26 @@ func createWorker(ctx context.Context, t *testing.T, db *DB, updaters ...func(*W
|
|||||||
|
|
||||||
// createWorkerFrom duplicates the given worker, ensuring new UUIDs.
|
// createWorkerFrom duplicates the given worker, ensuring new UUIDs.
|
||||||
func createWorkerFrom(ctx context.Context, t *testing.T, db *DB, worker Worker) *Worker {
|
func createWorkerFrom(ctx context.Context, t *testing.T, db *DB, worker Worker) *Worker {
|
||||||
worker.ID = 0
|
newWorker := sqlc.Worker{
|
||||||
worker.UUID = uuid.New()
|
UUID: uuid.New(),
|
||||||
worker.Name += " (copy)"
|
Secret: worker.Secret,
|
||||||
|
Name: worker.Name + " (copy)",
|
||||||
|
Address: worker.Address,
|
||||||
|
Platform: worker.Platform,
|
||||||
|
Software: worker.Software,
|
||||||
|
Status: worker.Status,
|
||||||
|
LastSeenAt: nullTimeToUTC(worker.LastSeenAt),
|
||||||
|
StatusRequested: worker.StatusRequested,
|
||||||
|
LazyStatusRequest: worker.LazyStatusRequest,
|
||||||
|
SupportedTaskTypes: worker.SupportedTaskTypes,
|
||||||
|
DeletedAt: worker.DeletedAt,
|
||||||
|
CanRestart: worker.CanRestart,
|
||||||
|
}
|
||||||
|
|
||||||
err := db.SaveWorker(ctx, &worker)
|
err := db.CreateWorker(ctx, &newWorker)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
dbWorker, err := db.FetchWorker(ctx, worker.UUID)
|
dbWorker, err := db.FetchWorker(ctx, newWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return dbWorker
|
return dbWorker
|
||||||
|
41
internal/manager/persistence/sqlc/methods.go
Normal file
41
internal/manager/persistence/sqlc/methods.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Code MANUALLY written to extend the SQLC structs with some extra methods.
|
||||||
|
|
||||||
|
package sqlc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
func (w *Worker) Identifier() string {
|
||||||
|
// Avoid a panic when worker.Identifier() is called on a nil pointer.
|
||||||
|
if w == nil {
|
||||||
|
return "-nil worker-"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (%s)", w.Name, w.UUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TaskTypes returns the worker's supported task types as list of strings.
|
||||||
|
func (w *Worker) TaskTypes() []string {
|
||||||
|
return strings.Split(w.SupportedTaskTypes, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusChangeRequest stores a requested status change on the Worker.
|
||||||
|
// This just updates the Worker instance, but doesn't store the change in the
|
||||||
|
// database.
|
||||||
|
func (w *Worker) StatusChangeRequest(status api.WorkerStatus, isLazyRequest bool) {
|
||||||
|
w.StatusRequested = status
|
||||||
|
w.LazyStatusRequest = isLazyRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusChangeClear clears the requested status change of the Worker.
|
||||||
|
// This just updates the Worker instance, but doesn't store the change in the
|
||||||
|
// database.
|
||||||
|
func (w *Worker) StatusChangeClear() {
|
||||||
|
w.StatusRequested = ""
|
||||||
|
w.LazyStatusRequest = false
|
||||||
|
}
|
@ -8,6 +8,8 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Job struct {
|
type Job struct {
|
||||||
@ -18,7 +20,7 @@ type Job struct {
|
|||||||
Name string
|
Name string
|
||||||
JobType string
|
JobType string
|
||||||
Priority int64
|
Priority int64
|
||||||
Status string
|
Status api.JobStatus
|
||||||
Activity string
|
Activity string
|
||||||
Settings json.RawMessage
|
Settings json.RawMessage
|
||||||
Metadata json.RawMessage
|
Metadata json.RawMessage
|
||||||
@ -64,7 +66,7 @@ type Task struct {
|
|||||||
JobID int64
|
JobID int64
|
||||||
IndexInJob int64
|
IndexInJob int64
|
||||||
Priority int64
|
Priority int64
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
WorkerID sql.NullInt64
|
WorkerID sql.NullInt64
|
||||||
LastTouchedAt sql.NullTime
|
LastTouchedAt sql.NullTime
|
||||||
Commands json.RawMessage
|
Commands json.RawMessage
|
||||||
@ -92,9 +94,9 @@ type Worker struct {
|
|||||||
Address string
|
Address string
|
||||||
Platform string
|
Platform string
|
||||||
Software string
|
Software string
|
||||||
Status string
|
Status api.WorkerStatus
|
||||||
LastSeenAt sql.NullTime
|
LastSeenAt sql.NullTime
|
||||||
StatusRequested string
|
StatusRequested api.WorkerStatus
|
||||||
LazyStatusRequest bool
|
LazyStatusRequest bool
|
||||||
SupportedTaskTypes string
|
SupportedTaskTypes string
|
||||||
DeletedAt sql.NullTime
|
DeletedAt sql.NullTime
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const addWorkerToJobBlocklist = `-- name: AddWorkerToJobBlocklist :exec
|
const addWorkerToJobBlocklist = `-- name: AddWorkerToJobBlocklist :exec
|
||||||
@ -156,7 +158,7 @@ type CreateJobParams struct {
|
|||||||
Name string
|
Name string
|
||||||
JobType string
|
JobType string
|
||||||
Priority int64
|
Priority int64
|
||||||
Status string
|
Status api.JobStatus
|
||||||
Activity string
|
Activity string
|
||||||
Settings json.RawMessage
|
Settings json.RawMessage
|
||||||
Metadata json.RawMessage
|
Metadata json.RawMessage
|
||||||
@ -218,7 +220,7 @@ type CreateTaskParams struct {
|
|||||||
JobID int64
|
JobID int64
|
||||||
IndexInJob int64
|
IndexInJob int64
|
||||||
Priority int64
|
Priority int64
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
Commands json.RawMessage
|
Commands json.RawMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,7 +466,7 @@ const fetchJobsInStatus = `-- name: FetchJobsInStatus :many
|
|||||||
SELECT id, created_at, updated_at, uuid, name, job_type, priority, status, activity, settings, metadata, delete_requested_at, storage_shaman_checkout_id, worker_tag_id FROM jobs WHERE status IN (/*SLICE:statuses*/?)
|
SELECT id, created_at, updated_at, uuid, name, job_type, priority, status, activity, settings, metadata, delete_requested_at, storage_shaman_checkout_id, worker_tag_id FROM jobs WHERE status IN (/*SLICE:statuses*/?)
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) FetchJobsInStatus(ctx context.Context, statuses []string) ([]Job, error) {
|
func (q *Queries) FetchJobsInStatus(ctx context.Context, statuses []api.JobStatus) ([]Job, error) {
|
||||||
query := fetchJobsInStatus
|
query := fetchJobsInStatus
|
||||||
var queryParams []interface{}
|
var queryParams []interface{}
|
||||||
if len(statuses) > 0 {
|
if len(statuses) > 0 {
|
||||||
@ -675,7 +677,7 @@ WHERE tasks.job_id = ?1
|
|||||||
|
|
||||||
type FetchTasksOfJobInStatusParams struct {
|
type FetchTasksOfJobInStatusParams struct {
|
||||||
JobID int64
|
JobID int64
|
||||||
TaskStatus []string
|
TaskStatus []api.TaskStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type FetchTasksOfJobInStatusRow struct {
|
type FetchTasksOfJobInStatusRow struct {
|
||||||
@ -743,7 +745,7 @@ WHERE tasks.worker_id = ?1
|
|||||||
|
|
||||||
type FetchTasksOfWorkerInStatusParams struct {
|
type FetchTasksOfWorkerInStatusParams struct {
|
||||||
WorkerID sql.NullInt64
|
WorkerID sql.NullInt64
|
||||||
TaskStatus string
|
TaskStatus api.TaskStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type FetchTasksOfWorkerInStatusRow struct {
|
type FetchTasksOfWorkerInStatusRow struct {
|
||||||
@ -801,7 +803,7 @@ WHERE tasks.worker_id = ?1
|
|||||||
type FetchTasksOfWorkerInStatusOfJobParams struct {
|
type FetchTasksOfWorkerInStatusOfJobParams struct {
|
||||||
WorkerID sql.NullInt64
|
WorkerID sql.NullInt64
|
||||||
JobID int64
|
JobID int64
|
||||||
TaskStatus string
|
TaskStatus api.TaskStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type FetchTasksOfWorkerInStatusOfJobRow struct {
|
type FetchTasksOfWorkerInStatusOfJobRow struct {
|
||||||
@ -855,7 +857,7 @@ AND last_touched_at <= ?2
|
|||||||
`
|
`
|
||||||
|
|
||||||
type FetchTimedOutTasksParams struct {
|
type FetchTimedOutTasksParams struct {
|
||||||
TaskStatus string
|
TaskStatus api.TaskStatus
|
||||||
UntouchedSince sql.NullTime
|
UntouchedSince sql.NullTime
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -916,7 +918,7 @@ GROUP BY status
|
|||||||
`
|
`
|
||||||
|
|
||||||
type JobCountTaskStatusesRow struct {
|
type JobCountTaskStatusesRow struct {
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
NumTasks int64
|
NumTasks int64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -951,7 +953,7 @@ WHERE job_id = ?1 AND status = ?2
|
|||||||
|
|
||||||
type JobCountTasksInStatusParams struct {
|
type JobCountTasksInStatusParams struct {
|
||||||
JobID int64
|
JobID int64
|
||||||
TaskStatus string
|
TaskStatus api.TaskStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch number of tasks in the given status, of the given job.
|
// Fetch number of tasks in the given status, of the given job.
|
||||||
@ -975,7 +977,7 @@ type QueryJobTaskSummariesRow struct {
|
|||||||
Name string
|
Name string
|
||||||
IndexInJob int64
|
IndexInJob int64
|
||||||
Priority int64
|
Priority int64
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
Type string
|
Type string
|
||||||
UpdatedAt sql.NullTime
|
UpdatedAt sql.NullTime
|
||||||
}
|
}
|
||||||
@ -1097,7 +1099,7 @@ UPDATE jobs SET updated_at=?1, status=?2, activity=?3 WHERE id=?4
|
|||||||
|
|
||||||
type SaveJobStatusParams struct {
|
type SaveJobStatusParams struct {
|
||||||
Now sql.NullTime
|
Now sql.NullTime
|
||||||
Status string
|
Status api.JobStatus
|
||||||
Activity string
|
Activity string
|
||||||
ID int64
|
ID int64
|
||||||
}
|
}
|
||||||
@ -1170,7 +1172,7 @@ GROUP BY status
|
|||||||
`
|
`
|
||||||
|
|
||||||
type SummarizeJobStatusesRow struct {
|
type SummarizeJobStatusesRow struct {
|
||||||
Status string
|
Status api.JobStatus
|
||||||
StatusCount int64
|
StatusCount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,7 +1377,7 @@ WHERE job_id = ?4
|
|||||||
|
|
||||||
type UpdateJobsTaskStatusesParams struct {
|
type UpdateJobsTaskStatusesParams struct {
|
||||||
UpdatedAt sql.NullTime
|
UpdatedAt sql.NullTime
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
Activity string
|
Activity string
|
||||||
JobID int64
|
JobID int64
|
||||||
}
|
}
|
||||||
@ -1400,10 +1402,10 @@ WHERE job_id = ?4 AND status in (/*SLICE:statuses_to_update*/?)
|
|||||||
|
|
||||||
type UpdateJobsTaskStatusesConditionalParams struct {
|
type UpdateJobsTaskStatusesConditionalParams struct {
|
||||||
UpdatedAt sql.NullTime
|
UpdatedAt sql.NullTime
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
Activity string
|
Activity string
|
||||||
JobID int64
|
JobID int64
|
||||||
StatusesToUpdate []string
|
StatusesToUpdate []api.TaskStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) UpdateJobsTaskStatusesConditional(ctx context.Context, arg UpdateJobsTaskStatusesConditionalParams) error {
|
func (q *Queries) UpdateJobsTaskStatusesConditional(ctx context.Context, arg UpdateJobsTaskStatusesConditionalParams) error {
|
||||||
@ -1444,7 +1446,7 @@ type UpdateTaskParams struct {
|
|||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
Priority int64
|
Priority int64
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
WorkerID sql.NullInt64
|
WorkerID sql.NullInt64
|
||||||
LastTouchedAt sql.NullTime
|
LastTouchedAt sql.NullTime
|
||||||
Commands json.RawMessage
|
Commands json.RawMessage
|
||||||
@ -1496,7 +1498,7 @@ WHERE id=?3
|
|||||||
|
|
||||||
type UpdateTaskStatusParams struct {
|
type UpdateTaskStatusParams struct {
|
||||||
UpdatedAt sql.NullTime
|
UpdatedAt sql.NullTime
|
||||||
Status string
|
Status api.TaskStatus
|
||||||
ID int64
|
ID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const assignTaskToWorker = `-- name: AssignTaskToWorker :exec
|
const assignTaskToWorker = `-- name: AssignTaskToWorker :exec
|
||||||
@ -39,9 +41,9 @@ LIMIT 1
|
|||||||
`
|
`
|
||||||
|
|
||||||
type FetchAssignedAndRunnableTaskOfWorkerParams struct {
|
type FetchAssignedAndRunnableTaskOfWorkerParams struct {
|
||||||
ActiveTaskStatus string
|
ActiveTaskStatus api.TaskStatus
|
||||||
WorkerID sql.NullInt64
|
WorkerID sql.NullInt64
|
||||||
ActiveJobStatuses []string
|
ActiveJobStatuses []api.JobStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type FetchAssignedAndRunnableTaskOfWorkerRow struct {
|
type FetchAssignedAndRunnableTaskOfWorkerRow struct {
|
||||||
@ -99,8 +101,8 @@ LIMIT 1
|
|||||||
`
|
`
|
||||||
|
|
||||||
type FetchWorkerTaskParams struct {
|
type FetchWorkerTaskParams struct {
|
||||||
TaskStatusActive string
|
TaskStatusActive api.TaskStatus
|
||||||
JobStatusActive string
|
JobStatusActive api.JobStatus
|
||||||
WorkerID sql.NullInt64
|
WorkerID sql.NullInt64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,10 +181,10 @@ ORDER BY jobs.priority DESC, tasks.priority DESC
|
|||||||
|
|
||||||
type FindRunnableTaskParams struct {
|
type FindRunnableTaskParams struct {
|
||||||
WorkerID int64
|
WorkerID int64
|
||||||
TaskStatusCompleted string
|
TaskStatusCompleted api.TaskStatus
|
||||||
WorkerTags []sql.NullInt64
|
WorkerTags []sql.NullInt64
|
||||||
SchedulableTaskStatuses []string
|
SchedulableTaskStatuses []api.TaskStatus
|
||||||
SchedulableJobStatuses []string
|
SchedulableJobStatuses []api.JobStatus
|
||||||
SupportedTaskTypes []string
|
SupportedTaskTypes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ FROM worker_tag_membership
|
|||||||
WHERE worker_id=@worker_id;
|
WHERE worker_id=@worker_id;
|
||||||
|
|
||||||
-- name: FetchWorkers :many
|
-- name: FetchWorkers :many
|
||||||
SELECT sqlc.embed(workers) FROM workers
|
SELECT * FROM workers
|
||||||
WHERE deleted_at IS NULL;
|
WHERE deleted_at IS NULL;
|
||||||
|
|
||||||
-- name: FetchWorker :one
|
-- name: FetchWorker :one
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const countWorkerTags = `-- name: CountWorkerTags :one
|
const countWorkerTags = `-- name: CountWorkerTags :one
|
||||||
@ -66,9 +68,9 @@ type CreateWorkerParams struct {
|
|||||||
Address string
|
Address string
|
||||||
Platform string
|
Platform string
|
||||||
Software string
|
Software string
|
||||||
Status string
|
Status api.WorkerStatus
|
||||||
LastSeenAt sql.NullTime
|
LastSeenAt sql.NullTime
|
||||||
StatusRequested string
|
StatusRequested api.WorkerStatus
|
||||||
LazyStatusRequest bool
|
LazyStatusRequest bool
|
||||||
SupportedTaskTypes string
|
SupportedTaskTypes string
|
||||||
DeletedAt sql.NullTime
|
DeletedAt sql.NullTime
|
||||||
@ -232,7 +234,7 @@ AND status NOT IN (/*SLICE:worker_statuses_no_timeout*/?)
|
|||||||
|
|
||||||
type FetchTimedOutWorkersParams struct {
|
type FetchTimedOutWorkersParams struct {
|
||||||
LastSeenBefore sql.NullTime
|
LastSeenBefore sql.NullTime
|
||||||
WorkerStatusesNoTimeout []string
|
WorkerStatusesNoTimeout []api.WorkerStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) FetchTimedOutWorkers(ctx context.Context, arg FetchTimedOutWorkersParams) ([]Worker, error) {
|
func (q *Queries) FetchTimedOutWorkers(ctx context.Context, arg FetchTimedOutWorkersParams) ([]Worker, error) {
|
||||||
@ -548,40 +550,36 @@ func (q *Queries) FetchWorkerUnconditionalByID(ctx context.Context, workerID int
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fetchWorkers = `-- name: FetchWorkers :many
|
const fetchWorkers = `-- name: FetchWorkers :many
|
||||||
SELECT workers.id, workers.created_at, workers.updated_at, workers.uuid, workers.secret, workers.name, workers.address, workers.platform, workers.software, workers.status, workers.last_seen_at, workers.status_requested, workers.lazy_status_request, workers.supported_task_types, workers.deleted_at, workers.can_restart FROM workers
|
SELECT id, created_at, updated_at, uuid, secret, name, address, platform, software, status, last_seen_at, status_requested, lazy_status_request, supported_task_types, deleted_at, can_restart FROM workers
|
||||||
WHERE deleted_at IS NULL
|
WHERE deleted_at IS NULL
|
||||||
`
|
`
|
||||||
|
|
||||||
type FetchWorkersRow struct {
|
func (q *Queries) FetchWorkers(ctx context.Context) ([]Worker, error) {
|
||||||
Worker Worker
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) FetchWorkers(ctx context.Context) ([]FetchWorkersRow, error) {
|
|
||||||
rows, err := q.db.QueryContext(ctx, fetchWorkers)
|
rows, err := q.db.QueryContext(ctx, fetchWorkers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var items []FetchWorkersRow
|
var items []Worker
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var i FetchWorkersRow
|
var i Worker
|
||||||
if err := rows.Scan(
|
if err := rows.Scan(
|
||||||
&i.Worker.ID,
|
&i.ID,
|
||||||
&i.Worker.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Worker.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.Worker.UUID,
|
&i.UUID,
|
||||||
&i.Worker.Secret,
|
&i.Secret,
|
||||||
&i.Worker.Name,
|
&i.Name,
|
||||||
&i.Worker.Address,
|
&i.Address,
|
||||||
&i.Worker.Platform,
|
&i.Platform,
|
||||||
&i.Worker.Software,
|
&i.Software,
|
||||||
&i.Worker.Status,
|
&i.Status,
|
||||||
&i.Worker.LastSeenAt,
|
&i.LastSeenAt,
|
||||||
&i.Worker.StatusRequested,
|
&i.StatusRequested,
|
||||||
&i.Worker.LazyStatusRequest,
|
&i.LazyStatusRequest,
|
||||||
&i.Worker.SupportedTaskTypes,
|
&i.SupportedTaskTypes,
|
||||||
&i.Worker.DeletedAt,
|
&i.DeletedAt,
|
||||||
&i.Worker.CanRestart,
|
&i.CanRestart,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -622,9 +620,9 @@ type SaveWorkerParams struct {
|
|||||||
Address string
|
Address string
|
||||||
Platform string
|
Platform string
|
||||||
Software string
|
Software string
|
||||||
Status string
|
Status api.WorkerStatus
|
||||||
LastSeenAt sql.NullTime
|
LastSeenAt sql.NullTime
|
||||||
StatusRequested string
|
StatusRequested api.WorkerStatus
|
||||||
LazyStatusRequest bool
|
LazyStatusRequest bool
|
||||||
SupportedTaskTypes string
|
SupportedTaskTypes string
|
||||||
CanRestart bool
|
CanRestart bool
|
||||||
@ -662,8 +660,8 @@ WHERE id=?5
|
|||||||
|
|
||||||
type SaveWorkerStatusParams struct {
|
type SaveWorkerStatusParams struct {
|
||||||
UpdatedAt sql.NullTime
|
UpdatedAt sql.NullTime
|
||||||
Status string
|
Status api.WorkerStatus
|
||||||
StatusRequested string
|
StatusRequested api.WorkerStatus
|
||||||
LazyStatusRequest bool
|
LazyStatusRequest bool
|
||||||
ID int64
|
ID int64
|
||||||
}
|
}
|
||||||
@ -808,7 +806,7 @@ GROUP BY status
|
|||||||
`
|
`
|
||||||
|
|
||||||
type SummarizeWorkerStatusesRow struct {
|
type SummarizeWorkerStatusesRow struct {
|
||||||
Status string
|
Status api.WorkerStatus
|
||||||
StatusCount int64
|
StatusCount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +77,8 @@ func (db *DB) scheduleTask(ctx context.Context, queries *sqlc.Queries, w *Worker
|
|||||||
// Worker, but since it's active that is unlikely.
|
// Worker, but since it's active that is unlikely.
|
||||||
{
|
{
|
||||||
row, err := queries.FetchAssignedAndRunnableTaskOfWorker(ctx, sqlc.FetchAssignedAndRunnableTaskOfWorkerParams{
|
row, err := queries.FetchAssignedAndRunnableTaskOfWorker(ctx, sqlc.FetchAssignedAndRunnableTaskOfWorkerParams{
|
||||||
ActiveTaskStatus: string(api.TaskStatusActive),
|
ActiveTaskStatus: api.TaskStatusActive,
|
||||||
ActiveJobStatuses: convertJobStatuses(schedulableJobStatuses),
|
ActiveJobStatuses: schedulableJobStatuses,
|
||||||
WorkerID: workerID,
|
WorkerID: workerID,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -141,18 +141,22 @@ func findTaskForWorker(
|
|||||||
w *Worker,
|
w *Worker,
|
||||||
) (sqlc.Task, error) {
|
) (sqlc.Task, error) {
|
||||||
|
|
||||||
// Construct the list of worker tags to check.
|
// Construct the list of worker tag IDs to check.
|
||||||
workerTags := make([]sql.NullInt64, len(w.Tags))
|
tags, err := queries.FetchTagsOfWorker(ctx, w.UUID)
|
||||||
for index, tag := range w.Tags {
|
if err != nil {
|
||||||
workerTags[index] = sql.NullInt64{Int64: int64(tag.ID), Valid: true}
|
return sqlc.Task{}, err
|
||||||
|
}
|
||||||
|
workerTags := make([]sql.NullInt64, len(tags))
|
||||||
|
for index, tag := range tags {
|
||||||
|
workerTags[index] = sql.NullInt64{Int64: tag.ID, Valid: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
row, err := queries.FindRunnableTask(ctx, sqlc.FindRunnableTaskParams{
|
row, err := queries.FindRunnableTask(ctx, sqlc.FindRunnableTaskParams{
|
||||||
WorkerID: int64(w.ID),
|
WorkerID: int64(w.ID),
|
||||||
SchedulableTaskStatuses: convertTaskStatuses(schedulableTaskStatuses),
|
SchedulableTaskStatuses: schedulableTaskStatuses,
|
||||||
SchedulableJobStatuses: convertJobStatuses(schedulableJobStatuses),
|
SchedulableJobStatuses: schedulableJobStatuses,
|
||||||
SupportedTaskTypes: w.TaskTypes(),
|
SupportedTaskTypes: w.TaskTypes(),
|
||||||
TaskStatusCompleted: string(api.TaskStatusCompleted),
|
TaskStatusCompleted: api.TaskStatusCompleted,
|
||||||
WorkerTags: workerTags,
|
WorkerTags: workerTags,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -48,7 +48,7 @@ func TestOneJobOneTask(t *testing.T) {
|
|||||||
require.NotNil(t, task)
|
require.NotNil(t, task)
|
||||||
assert.Equal(t, job.ID, task.JobID)
|
assert.Equal(t, job.ID, task.JobID)
|
||||||
require.NotNil(t, task.WorkerID, "no worker assigned to returned task")
|
require.NotNil(t, task.WorkerID, "no worker assigned to returned task")
|
||||||
assert.Equal(t, w.ID, *task.WorkerID, "task must be assigned to the requesting worker")
|
assert.Equal(t, w.ID, int64(*task.WorkerID), "task must be assigned to the requesting worker")
|
||||||
|
|
||||||
// Check the task in the database.
|
// Check the task in the database.
|
||||||
now := db.now()
|
now := db.now()
|
||||||
@ -57,7 +57,7 @@ func TestOneJobOneTask(t *testing.T) {
|
|||||||
require.NotNil(t, dbTask)
|
require.NotNil(t, dbTask)
|
||||||
require.NotNil(t, dbTask.WorkerID, "no worker assigned to task in database")
|
require.NotNil(t, dbTask.WorkerID, "no worker assigned to task in database")
|
||||||
|
|
||||||
assert.Equal(t, w.ID, *dbTask.WorkerID, "task must be assigned to the requesting worker")
|
assert.Equal(t, w.ID, int64(*dbTask.WorkerID), "task must be assigned to the requesting worker")
|
||||||
assert.WithinDuration(t, now, dbTask.LastTouchedAt, time.Second, "task must be 'touched' by the worker after scheduling")
|
assert.WithinDuration(t, now, dbTask.LastTouchedAt, time.Second, "task must be 'touched' by the worker after scheduling")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ func TestAlreadyAssigned(t *testing.T) {
|
|||||||
// another, higher-prio task to be done.
|
// another, higher-prio task to be done.
|
||||||
dbTask3, err := db.FetchTask(ctx, att3.UUID)
|
dbTask3, err := db.FetchTask(ctx, att3.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dbTask3.WorkerID = &w.ID
|
dbTask3.WorkerID = ptr(uint(w.ID))
|
||||||
dbTask3.Status = api.TaskStatusActive
|
dbTask3.Status = api.TaskStatusActive
|
||||||
err = db.SaveTask(ctx, dbTask3)
|
err = db.SaveTask(ctx, dbTask3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -292,7 +292,7 @@ func TestAssignedToOtherWorker(t *testing.T) {
|
|||||||
// it shouldn't matter which worker it's assigned to.
|
// it shouldn't matter which worker it's assigned to.
|
||||||
dbTask2, err := db.FetchTask(ctx, att2.UUID)
|
dbTask2, err := db.FetchTask(ctx, att2.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dbTask2.WorkerID = &w2.ID
|
dbTask2.WorkerID = ptr(uint(w2.ID))
|
||||||
dbTask2.Status = api.TaskStatusQueued
|
dbTask2.Status = api.TaskStatusQueued
|
||||||
err = db.SaveTask(ctx, dbTask2)
|
err = db.SaveTask(ctx, dbTask2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -302,7 +302,7 @@ func TestAssignedToOtherWorker(t *testing.T) {
|
|||||||
require.NotNil(t, task)
|
require.NotNil(t, task)
|
||||||
|
|
||||||
assert.Equal(t, att2.Name, task.Name, "the high-prio task should have been chosen")
|
assert.Equal(t, att2.Name, task.Name, "the high-prio task should have been chosen")
|
||||||
assert.Equal(t, *task.WorkerID, w.ID, "the task should now be assigned to the worker it was scheduled for")
|
assert.Equal(t, int64(*task.WorkerID), w.ID, "the task should now be assigned to the worker it was scheduled for")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPreviouslyFailed(t *testing.T) {
|
func TestPreviouslyFailed(t *testing.T) {
|
||||||
@ -344,14 +344,12 @@ func TestWorkerTagJobWithTag(t *testing.T) {
|
|||||||
require.NoError(t, db.CreateWorkerTag(ctx, &tag2))
|
require.NoError(t, db.CreateWorkerTag(ctx, &tag2))
|
||||||
|
|
||||||
// Create a worker in tag1:
|
// Create a worker in tag1:
|
||||||
workerC := linuxWorker(t, db, func(w *Worker) {
|
workerC := linuxWorker(t, db)
|
||||||
w.Tags = []*WorkerTag{&tag1}
|
require.NoError(t, db.WorkerSetTags(ctx, &workerC, []string{tag1.UUID}))
|
||||||
})
|
|
||||||
|
|
||||||
// Create a worker without tag:
|
// Create a worker without tag:
|
||||||
workerNC := linuxWorker(t, db, func(w *Worker) {
|
workerNC := linuxWorker(t, db, func(w *Worker) {
|
||||||
w.UUID = "c53f8f68-4149-4790-991c-ba73a326551e"
|
w.UUID = "c53f8f68-4149-4790-991c-ba73a326551e"
|
||||||
w.Tags = nil
|
|
||||||
})
|
})
|
||||||
|
|
||||||
{ // Test job with different tag:
|
{ // Test job with different tag:
|
||||||
@ -391,14 +389,12 @@ func TestWorkerTagJobWithoutTag(t *testing.T) {
|
|||||||
require.NoError(t, db.CreateWorkerTag(ctx, &tag1))
|
require.NoError(t, db.CreateWorkerTag(ctx, &tag1))
|
||||||
|
|
||||||
// Create a worker in tag1:
|
// Create a worker in tag1:
|
||||||
workerC := linuxWorker(t, db, func(w *Worker) {
|
workerC := linuxWorker(t, db)
|
||||||
w.Tags = []*WorkerTag{&tag1}
|
require.NoError(t, db.WorkerSetTags(ctx, &workerC, []string{tag1.UUID}))
|
||||||
})
|
|
||||||
|
|
||||||
// Create a worker without tag:
|
// Create a worker without tag:
|
||||||
workerNC := linuxWorker(t, db, func(w *Worker) {
|
workerNC := linuxWorker(t, db, func(w *Worker) {
|
||||||
w.UUID = "c53f8f68-4149-4790-991c-ba73a326551e"
|
w.UUID = "c53f8f68-4149-4790-991c-ba73a326551e"
|
||||||
w.Tags = nil
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test tag-less job:
|
// Test tag-less job:
|
||||||
@ -537,9 +533,9 @@ func saveTestWorker(t *testing.T, db *DB, worker *Worker) {
|
|||||||
Address: worker.Address,
|
Address: worker.Address,
|
||||||
Platform: worker.Platform,
|
Platform: worker.Platform,
|
||||||
Software: worker.Software,
|
Software: worker.Software,
|
||||||
Status: string(worker.Status),
|
Status: worker.Status,
|
||||||
LastSeenAt: sql.NullTime{Time: worker.LastSeenAt, Valid: !worker.LastSeenAt.IsZero()},
|
LastSeenAt: nullTimeToUTC(worker.LastSeenAt),
|
||||||
StatusRequested: string(worker.StatusRequested),
|
StatusRequested: worker.StatusRequested,
|
||||||
LazyStatusRequest: worker.LazyStatusRequest,
|
LazyStatusRequest: worker.LazyStatusRequest,
|
||||||
SupportedTaskTypes: worker.SupportedTaskTypes,
|
SupportedTaskTypes: worker.SupportedTaskTypes,
|
||||||
DeletedAt: sql.NullTime(worker.DeletedAt),
|
DeletedAt: sql.NullTime(worker.DeletedAt),
|
||||||
@ -550,5 +546,6 @@ func saveTestWorker(t *testing.T, db *DB, worker *Worker) {
|
|||||||
id, err := queries.CreateWorker(context.TODO(), params)
|
id, err := queries.CreateWorker(context.TODO(), params)
|
||||||
require.NoError(t, err, "cannot save worker %q", worker.Name)
|
require.NoError(t, err, "cannot save worker %q", worker.Name)
|
||||||
|
|
||||||
worker.ID = uint(id)
|
worker.ID = id
|
||||||
|
worker.CreatedAt = params.CreatedAt
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func (db *DB) FetchTimedOutTasks(ctx context.Context, untouchedSince time.Time)
|
|||||||
queries := db.queries()
|
queries := db.queries()
|
||||||
|
|
||||||
sqlcTasks, err := queries.FetchTimedOutTasks(ctx, sqlc.FetchTimedOutTasksParams{
|
sqlcTasks, err := queries.FetchTimedOutTasks(ctx, sqlc.FetchTimedOutTasksParams{
|
||||||
TaskStatus: string(api.TaskStatusActive),
|
TaskStatus: api.TaskStatusActive,
|
||||||
UntouchedSince: sql.NullTime{Time: untouchedSince, Valid: true},
|
UntouchedSince: sql.NullTime{Time: untouchedSince, Valid: true},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -54,13 +54,8 @@ func (db *DB) FetchTimedOutTasks(ctx context.Context, untouchedSince time.Time)
|
|||||||
func (db *DB) FetchTimedOutWorkers(ctx context.Context, lastSeenBefore time.Time) ([]*Worker, error) {
|
func (db *DB) FetchTimedOutWorkers(ctx context.Context, lastSeenBefore time.Time) ([]*Worker, error) {
|
||||||
queries := db.queries()
|
queries := db.queries()
|
||||||
|
|
||||||
statuses := make([]string, len(workerStatusNoTimeout))
|
|
||||||
for i, status := range workerStatusNoTimeout {
|
|
||||||
statuses[i] = string(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlcWorkers, err := queries.FetchTimedOutWorkers(ctx, sqlc.FetchTimedOutWorkersParams{
|
sqlcWorkers, err := queries.FetchTimedOutWorkers(ctx, sqlc.FetchTimedOutWorkersParams{
|
||||||
WorkerStatusesNoTimeout: statuses,
|
WorkerStatusesNoTimeout: workerStatusNoTimeout,
|
||||||
LastSeenBefore: sql.NullTime{
|
LastSeenBefore: sql.NullTime{
|
||||||
Time: lastSeenBefore.UTC(),
|
Time: lastSeenBefore.UTC(),
|
||||||
Valid: true},
|
Valid: true},
|
||||||
@ -71,7 +66,7 @@ func (db *DB) FetchTimedOutWorkers(ctx context.Context, lastSeenBefore time.Time
|
|||||||
|
|
||||||
result := make([]*Worker, len(sqlcWorkers))
|
result := make([]*Worker, len(sqlcWorkers))
|
||||||
for index := range sqlcWorkers {
|
for index := range sqlcWorkers {
|
||||||
result[index] = convertSqlcWorker(sqlcWorkers[index])
|
result[index] = &sqlcWorkers[index]
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package persistence
|
package persistence
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -55,8 +56,8 @@ func TestFetchTimedOutWorkers(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
timeoutDeadline := mustParseTime("2022-06-07T11:14:47+02:00")
|
timeoutDeadline := mustParseTime("2022-06-07T11:14:47+02:00")
|
||||||
beforeDeadline := timeoutDeadline.Add(-10 * time.Second)
|
beforeDeadline := sql.NullTime{Time: timeoutDeadline.Add(-10 * time.Second), Valid: true}
|
||||||
afterDeadline := timeoutDeadline.Add(10 * time.Second)
|
afterDeadline := sql.NullTime{Time: timeoutDeadline.Add(10 * time.Second), Valid: true}
|
||||||
|
|
||||||
worker0 := Worker{ // Offline, so should not time out.
|
worker0 := Worker{ // Offline, so should not time out.
|
||||||
UUID: "c7b4d1d5-0a96-4e19-993f-028786d3d2c1",
|
UUID: "c7b4d1d5-0a96-4e19-993f-028786d3d2c1",
|
||||||
|
@ -60,7 +60,7 @@ func (db *DB) SetWorkerSleepSchedule(ctx context.Context, workerUUID string, sch
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("fetching worker %q: %w", workerUUID, err)
|
return fmt.Errorf("fetching worker %q: %w", workerUUID, err)
|
||||||
}
|
}
|
||||||
schedule.WorkerID = worker.ID
|
schedule.WorkerID = uint(worker.ID)
|
||||||
schedule.Worker = worker
|
schedule.Worker = worker
|
||||||
|
|
||||||
// Only store timestamps in UTC.
|
// Only store timestamps in UTC.
|
||||||
@ -120,7 +120,7 @@ func (db *DB) FetchSleepScheduleWorker(ctx context.Context, schedule *SleepSched
|
|||||||
return workerError(err, "finding worker by their sleep schedule")
|
return workerError(err, "finding worker by their sleep schedule")
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule.Worker = convertSqlcWorker(worker)
|
schedule.Worker = &worker
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ func TestFetchWorkerSleepSchedule(t *testing.T) {
|
|||||||
|
|
||||||
// Create a sleep schedule.
|
// Create a sleep schedule.
|
||||||
created := SleepSchedule{
|
created := SleepSchedule{
|
||||||
WorkerID: linuxWorker.ID,
|
WorkerID: uint(linuxWorker.ID),
|
||||||
Worker: &linuxWorker,
|
Worker: &linuxWorker,
|
||||||
|
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
@ -53,7 +53,7 @@ func TestFetchWorkerSleepSchedule(t *testing.T) {
|
|||||||
|
|
||||||
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertEqualSleepSchedule(t, linuxWorker.ID, created, *fetched)
|
assertEqualSleepSchedule(t, uint(linuxWorker.ID), created, *fetched)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchSleepScheduleWorker(t *testing.T) {
|
func TestFetchSleepScheduleWorker(t *testing.T) {
|
||||||
@ -74,7 +74,7 @@ func TestFetchSleepScheduleWorker(t *testing.T) {
|
|||||||
|
|
||||||
// Create a sleep schedule.
|
// Create a sleep schedule.
|
||||||
created := SleepSchedule{
|
created := SleepSchedule{
|
||||||
WorkerID: linuxWorker.ID,
|
WorkerID: uint(linuxWorker.ID),
|
||||||
Worker: &linuxWorker,
|
Worker: &linuxWorker,
|
||||||
|
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
@ -120,7 +120,7 @@ func TestSetWorkerSleepSchedule(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
schedule := SleepSchedule{
|
schedule := SleepSchedule{
|
||||||
WorkerID: linuxWorker.ID,
|
WorkerID: uint(linuxWorker.ID),
|
||||||
Worker: &linuxWorker,
|
Worker: &linuxWorker,
|
||||||
|
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
@ -138,7 +138,7 @@ func TestSetWorkerSleepSchedule(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fetched, err := db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
fetched, err := db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertEqualSleepSchedule(t, linuxWorker.ID, schedule, *fetched)
|
assertEqualSleepSchedule(t, uint(linuxWorker.ID), schedule, *fetched)
|
||||||
|
|
||||||
// Overwrite the schedule with one that already has a database ID.
|
// Overwrite the schedule with one that already has a database ID.
|
||||||
newSchedule := schedule
|
newSchedule := schedule
|
||||||
@ -150,11 +150,11 @@ func TestSetWorkerSleepSchedule(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertEqualSleepSchedule(t, linuxWorker.ID, newSchedule, *fetched)
|
assertEqualSleepSchedule(t, uint(linuxWorker.ID), newSchedule, *fetched)
|
||||||
|
|
||||||
// Overwrite the schedule with a freshly constructed one.
|
// Overwrite the schedule with a freshly constructed one.
|
||||||
newerSchedule := SleepSchedule{
|
newerSchedule := SleepSchedule{
|
||||||
WorkerID: linuxWorker.ID,
|
WorkerID: uint(linuxWorker.ID),
|
||||||
Worker: &linuxWorker,
|
Worker: &linuxWorker,
|
||||||
|
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
@ -166,11 +166,11 @@ func TestSetWorkerSleepSchedule(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertEqualSleepSchedule(t, linuxWorker.ID, newerSchedule, *fetched)
|
assertEqualSleepSchedule(t, uint(linuxWorker.ID), newerSchedule, *fetched)
|
||||||
|
|
||||||
// Clear the sleep schedule.
|
// Clear the sleep schedule.
|
||||||
emptySchedule := SleepSchedule{
|
emptySchedule := SleepSchedule{
|
||||||
WorkerID: linuxWorker.ID,
|
WorkerID: uint(linuxWorker.ID),
|
||||||
Worker: &linuxWorker,
|
Worker: &linuxWorker,
|
||||||
|
|
||||||
IsActive: false,
|
IsActive: false,
|
||||||
@ -182,7 +182,7 @@ func TestSetWorkerSleepSchedule(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
fetched, err = db.FetchWorkerSleepSchedule(ctx, linuxWorker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertEqualSleepSchedule(t, linuxWorker.ID, emptySchedule, *fetched)
|
assertEqualSleepSchedule(t, uint(linuxWorker.ID), emptySchedule, *fetched)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +212,7 @@ func TestSetWorkerSleepScheduleNextCheck(t *testing.T) {
|
|||||||
|
|
||||||
fetched, err := db.FetchWorkerSleepSchedule(ctx, schedule.Worker.UUID)
|
fetched, err := db.FetchWorkerSleepSchedule(ctx, schedule.Worker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assertEqualSleepSchedule(t, schedule.Worker.ID, schedule, *fetched)
|
assertEqualSleepSchedule(t, uint(schedule.Worker.ID), schedule, *fetched)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchSleepSchedulesToCheck(t *testing.T) {
|
func TestFetchSleepSchedulesToCheck(t *testing.T) {
|
||||||
@ -293,9 +293,9 @@ func TestFetchSleepSchedulesToCheck(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, toCheck, 2)
|
require.Len(t, toCheck, 2)
|
||||||
|
|
||||||
assertEqualSleepSchedule(t, schedule0.Worker.ID, schedule0, *toCheck[0])
|
assertEqualSleepSchedule(t, uint(schedule0.Worker.ID), schedule0, *toCheck[0])
|
||||||
assert.Nil(t, toCheck[0].Worker, "the Worker should NOT be fetched")
|
assert.Nil(t, toCheck[0].Worker, "the Worker should NOT be fetched")
|
||||||
assertEqualSleepSchedule(t, schedule2.Worker.ID, schedule1, *toCheck[1])
|
assertEqualSleepSchedule(t, uint(schedule2.Worker.ID), schedule1, *toCheck[1])
|
||||||
assert.Nil(t, toCheck[1].Worker, "the Worker should NOT be fetched")
|
assert.Nil(t, toCheck[1].Worker, "the Worker should NOT be fetched")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,3 +173,17 @@ func (db *DB) WorkerSetTags(ctx context.Context, worker *Worker, tagUUIDs []stri
|
|||||||
|
|
||||||
return qtx.commit()
|
return qtx.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) FetchTagsOfWorker(ctx context.Context, workerUUID string) ([]WorkerTag, error) {
|
||||||
|
queries := db.queries()
|
||||||
|
tags, err := queries.FetchTagsOfWorker(ctx, workerUUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, workerTagError(err, "fetching tags of worker %s", workerUUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
gormTags := make([]WorkerTag, len(tags))
|
||||||
|
for index, tag := range tags {
|
||||||
|
gormTags[index] = *convertSqlcWorkerTag(tag)
|
||||||
|
}
|
||||||
|
return gormTags, nil
|
||||||
|
}
|
||||||
|
@ -101,8 +101,11 @@ func TestAssignUnassignWorkerTags(t *testing.T) {
|
|||||||
w, err := f.db.FetchWorker(f.ctx, f.worker.UUID)
|
w, err := f.db.FetchWorker(f.ctx, f.worker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tags, err := f.db.queries().FetchTagsOfWorker(f.ctx, w.UUID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Catch doubly-reported tags, as the maps below would hide those cases.
|
// Catch doubly-reported tags, as the maps below would hide those cases.
|
||||||
assert.Len(t, w.Tags, len(tagUUIDs), msgLabel)
|
assert.Len(t, tags, len(tagUUIDs), msgLabel)
|
||||||
|
|
||||||
expectTags := make(map[string]bool)
|
expectTags := make(map[string]bool)
|
||||||
for _, cid := range tagUUIDs {
|
for _, cid := range tagUUIDs {
|
||||||
@ -110,8 +113,8 @@ func TestAssignUnassignWorkerTags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
actualTags := make(map[string]bool)
|
actualTags := make(map[string]bool)
|
||||||
for _, c := range w.Tags {
|
for _, tag := range tags {
|
||||||
actualTags[c.UUID] = true
|
actualTags[tag.UUID] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, expectTags, actualTags, msgLabel)
|
assert.Equal(t, expectTags, actualTags, msgLabel)
|
||||||
@ -171,9 +174,9 @@ func TestDeleteWorkerTagWithWorkersAssigned(t *testing.T) {
|
|||||||
require.NoError(t, f.db.DeleteWorkerTag(f.ctx, f.tag.UUID))
|
require.NoError(t, f.db.DeleteWorkerTag(f.ctx, f.tag.UUID))
|
||||||
|
|
||||||
// Check the Worker has been unassigned from the tag.
|
// Check the Worker has been unassigned from the tag.
|
||||||
w, err := f.db.FetchWorker(f.ctx, f.worker.UUID)
|
tags, err := f.db.queries().FetchTagsOfWorker(f.ctx, f.worker.UUID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, w.Tags)
|
assert.Empty(t, tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertTagsMatch(t *testing.T, f WorkerTestFixture, expectUUIDs ...string) {
|
func assertTagsMatch(t *testing.T, f WorkerTestFixture, expectUUIDs ...string) {
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@ -15,7 +14,9 @@ import (
|
|||||||
"projects.blender.org/studio/flamenco/pkg/api"
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Worker struct {
|
type Worker = sqlc.Worker
|
||||||
|
|
||||||
|
type Worker__gorm struct {
|
||||||
Model
|
Model
|
||||||
DeletedAt sql.NullTime
|
DeletedAt sql.NullTime
|
||||||
|
|
||||||
@ -38,40 +39,11 @@ type Worker struct {
|
|||||||
Tags []*WorkerTag
|
Tags []*WorkerTag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Worker) Identifier() string {
|
|
||||||
// Avoid a panic when worker.Identifier() is called on a nil pointer.
|
|
||||||
if w == nil {
|
|
||||||
return "-nil worker-"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s (%s)", w.Name, w.UUID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TaskTypes returns the worker's supported task types as list of strings.
|
|
||||||
func (w *Worker) TaskTypes() []string {
|
|
||||||
return strings.Split(w.SupportedTaskTypes, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusChangeRequest stores a requested status change on the Worker.
|
|
||||||
// This just updates the Worker instance, but doesn't store the change in the
|
|
||||||
// database.
|
|
||||||
func (w *Worker) StatusChangeRequest(status api.WorkerStatus, isLazyRequest bool) {
|
|
||||||
w.StatusRequested = status
|
|
||||||
w.LazyStatusRequest = isLazyRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusChangeClear clears the requested status change of the Worker.
|
|
||||||
// This just updates the Worker instance, but doesn't store the change in the
|
|
||||||
// database.
|
|
||||||
func (w *Worker) StatusChangeClear() {
|
|
||||||
w.StatusRequested = ""
|
|
||||||
w.LazyStatusRequest = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) CreateWorker(ctx context.Context, w *Worker) error {
|
func (db *DB) CreateWorker(ctx context.Context, w *Worker) error {
|
||||||
queries := db.queries()
|
queries := db.queries()
|
||||||
|
|
||||||
now := db.nowNullable().Time
|
now := db.nowNullable().Time
|
||||||
workerID, err := queries.CreateWorker(ctx, sqlc.CreateWorkerParams{
|
params := sqlc.CreateWorkerParams{
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UUID: w.UUID,
|
UUID: w.UUID,
|
||||||
Secret: w.Secret,
|
Secret: w.Secret,
|
||||||
@ -79,35 +51,22 @@ func (db *DB) CreateWorker(ctx context.Context, w *Worker) error {
|
|||||||
Address: w.Address,
|
Address: w.Address,
|
||||||
Platform: w.Platform,
|
Platform: w.Platform,
|
||||||
Software: w.Software,
|
Software: w.Software,
|
||||||
Status: string(w.Status),
|
Status: w.Status,
|
||||||
LastSeenAt: sql.NullTime{
|
LastSeenAt: nullTimeToUTC(w.LastSeenAt),
|
||||||
Time: w.LastSeenAt.UTC(),
|
StatusRequested: w.StatusRequested,
|
||||||
Valid: !w.LastSeenAt.IsZero(),
|
|
||||||
},
|
|
||||||
StatusRequested: string(w.StatusRequested),
|
|
||||||
LazyStatusRequest: w.LazyStatusRequest,
|
LazyStatusRequest: w.LazyStatusRequest,
|
||||||
SupportedTaskTypes: w.SupportedTaskTypes,
|
SupportedTaskTypes: w.SupportedTaskTypes,
|
||||||
DeletedAt: sql.NullTime(w.DeletedAt),
|
DeletedAt: sql.NullTime(w.DeletedAt),
|
||||||
CanRestart: w.CanRestart,
|
CanRestart: w.CanRestart,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
workerID, err := queries.CreateWorker(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating new worker: %w", err)
|
return fmt.Errorf("creating new worker: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.ID = uint(workerID)
|
w.ID = workerID
|
||||||
w.CreatedAt = now
|
w.CreatedAt = params.CreatedAt
|
||||||
|
|
||||||
// TODO: remove the create-with-tags functionality to a higher-level function.
|
|
||||||
// This code is just here to make this function work like the GORM code did.
|
|
||||||
for _, tag := range w.Tags {
|
|
||||||
err := queries.WorkerAddTagMembership(ctx, sqlc.WorkerAddTagMembershipParams{
|
|
||||||
WorkerTagID: int64(tag.ID),
|
|
||||||
WorkerID: workerID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -120,19 +79,7 @@ func (db *DB) FetchWorker(ctx context.Context, uuid string) (*Worker, error) {
|
|||||||
return nil, workerError(err, "fetching worker %s", uuid)
|
return nil, workerError(err, "fetching worker %s", uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this code, and let the caller fetch the tags when interested in them.
|
return &worker, nil
|
||||||
workerTags, err := queries.FetchTagsOfWorker(ctx, uuid)
|
|
||||||
if err != nil {
|
|
||||||
return nil, workerTagError(err, "fetching tags of worker %s", uuid)
|
|
||||||
}
|
|
||||||
|
|
||||||
convertedWorker := convertSqlcWorker(worker)
|
|
||||||
convertedWorker.Tags = make([]*WorkerTag, len(workerTags))
|
|
||||||
for index := range workerTags {
|
|
||||||
convertedWorker.Tags[index] = convertSqlcWorkerTag(workerTags[index])
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertedWorker, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) DeleteWorker(ctx context.Context, uuid string) error {
|
func (db *DB) DeleteWorker(ctx context.Context, uuid string) error {
|
||||||
@ -168,11 +115,11 @@ func (db *DB) FetchWorkers(ctx context.Context) ([]*Worker, error) {
|
|||||||
return nil, workerError(err, "fetching all workers")
|
return nil, workerError(err, "fetching all workers")
|
||||||
}
|
}
|
||||||
|
|
||||||
gormWorkers := make([]*Worker, len(workers))
|
workerPointers := make([]*Worker, len(workers))
|
||||||
for idx := range workers {
|
for idx := range workers {
|
||||||
gormWorkers[idx] = convertSqlcWorker(workers[idx].Worker)
|
workerPointers[idx] = &workers[idx]
|
||||||
}
|
}
|
||||||
return gormWorkers, nil
|
return workerPointers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetchWorkerTask returns the most recent task assigned to the given Worker.
|
// FetchWorkerTask returns the most recent task assigned to the given Worker.
|
||||||
@ -184,8 +131,8 @@ func (db *DB) FetchWorkerTask(ctx context.Context, worker *Worker) (*Task, error
|
|||||||
workerID := sql.NullInt64{Int64: int64(worker.ID), Valid: true}
|
workerID := sql.NullInt64{Int64: int64(worker.ID), Valid: true}
|
||||||
|
|
||||||
row, err := queries.FetchWorkerTask(ctx, sqlc.FetchWorkerTaskParams{
|
row, err := queries.FetchWorkerTask(ctx, sqlc.FetchWorkerTaskParams{
|
||||||
TaskStatusActive: string(api.TaskStatusActive),
|
TaskStatusActive: api.TaskStatusActive,
|
||||||
JobStatusActive: string(api.JobStatusActive),
|
JobStatusActive: api.JobStatusActive,
|
||||||
WorkerID: workerID,
|
WorkerID: workerID,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -224,10 +171,10 @@ func (db *DB) SaveWorkerStatus(ctx context.Context, w *Worker) error {
|
|||||||
|
|
||||||
err := queries.SaveWorkerStatus(ctx, sqlc.SaveWorkerStatusParams{
|
err := queries.SaveWorkerStatus(ctx, sqlc.SaveWorkerStatusParams{
|
||||||
UpdatedAt: db.nowNullable(),
|
UpdatedAt: db.nowNullable(),
|
||||||
Status: string(w.Status),
|
Status: w.Status,
|
||||||
StatusRequested: string(w.StatusRequested),
|
StatusRequested: w.StatusRequested,
|
||||||
LazyStatusRequest: w.LazyStatusRequest,
|
LazyStatusRequest: w.LazyStatusRequest,
|
||||||
ID: int64(w.ID),
|
ID: w.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("saving worker status: %w", err)
|
return fmt.Errorf("saving worker status: %w", err)
|
||||||
@ -235,10 +182,9 @@ func (db *DB) SaveWorkerStatus(ctx context.Context, w *Worker) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) SaveWorker(ctx context.Context, w *Worker) error {
|
func (db *DB) SaveWorker(ctx context.Context, w *sqlc.Worker) error {
|
||||||
// TODO: remove this code, and just let the caller call CreateWorker() directly.
|
|
||||||
if w.ID == 0 {
|
if w.ID == 0 {
|
||||||
return db.CreateWorker(ctx, w)
|
panic("Do not use SaveWorker() to create a new Worker, use CreateWorker() instead")
|
||||||
}
|
}
|
||||||
|
|
||||||
queries := db.queries()
|
queries := db.queries()
|
||||||
@ -251,13 +197,13 @@ func (db *DB) SaveWorker(ctx context.Context, w *Worker) error {
|
|||||||
Address: w.Address,
|
Address: w.Address,
|
||||||
Platform: w.Platform,
|
Platform: w.Platform,
|
||||||
Software: w.Software,
|
Software: w.Software,
|
||||||
Status: string(w.Status),
|
Status: w.Status,
|
||||||
LastSeenAt: sql.NullTime{Time: w.LastSeenAt, Valid: !w.LastSeenAt.IsZero()},
|
LastSeenAt: w.LastSeenAt,
|
||||||
StatusRequested: string(w.StatusRequested),
|
StatusRequested: w.StatusRequested,
|
||||||
LazyStatusRequest: w.LazyStatusRequest,
|
LazyStatusRequest: w.LazyStatusRequest,
|
||||||
SupportedTaskTypes: w.SupportedTaskTypes,
|
SupportedTaskTypes: w.SupportedTaskTypes,
|
||||||
CanRestart: w.CanRestart,
|
CanRestart: w.CanRestart,
|
||||||
ID: int64(w.ID),
|
ID: w.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("saving worker: %w", err)
|
return fmt.Errorf("saving worker: %w", err)
|
||||||
@ -303,34 +249,6 @@ func (db *DB) SummarizeWorkerStatuses(ctx context.Context) (WorkerStatusCount, e
|
|||||||
return statusCounts, nil
|
return statusCounts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertSqlcWorker converts a worker from the SQLC-generated model to the model
|
|
||||||
// expected by the rest of the code. This is mostly in place to aid in the GORM
|
|
||||||
// to SQLC migration. It is intended that eventually the rest of the code will
|
|
||||||
// use the same SQLC-generated model.
|
|
||||||
func convertSqlcWorker(worker sqlc.Worker) *Worker {
|
|
||||||
return &Worker{
|
|
||||||
Model: Model{
|
|
||||||
ID: uint(worker.ID),
|
|
||||||
CreatedAt: worker.CreatedAt,
|
|
||||||
UpdatedAt: worker.UpdatedAt.Time,
|
|
||||||
},
|
|
||||||
DeletedAt: worker.DeletedAt,
|
|
||||||
|
|
||||||
UUID: worker.UUID,
|
|
||||||
Secret: worker.Secret,
|
|
||||||
Name: worker.Name,
|
|
||||||
Address: worker.Address,
|
|
||||||
Platform: worker.Platform,
|
|
||||||
Software: worker.Software,
|
|
||||||
Status: api.WorkerStatus(worker.Status),
|
|
||||||
LastSeenAt: worker.LastSeenAt.Time,
|
|
||||||
CanRestart: worker.CanRestart,
|
|
||||||
StatusRequested: api.WorkerStatus(worker.StatusRequested),
|
|
||||||
LazyStatusRequest: worker.LazyStatusRequest,
|
|
||||||
SupportedTaskTypes: worker.SupportedTaskTypes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertSqlcWorkerTag converts a worker tag from the SQLC-generated model to
|
// convertSqlcWorkerTag converts a worker tag from the SQLC-generated model to
|
||||||
// the model expected by the rest of the code. This is mostly in place to aid in
|
// the model expected by the rest of the code. This is mostly in place to aid in
|
||||||
// the GORM to SQLC migration. It is intended that eventually the rest of the
|
// the GORM to SQLC migration. It is intended that eventually the rest of the
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
persistence "projects.blender.org/studio/flamenco/internal/manager/persistence"
|
persistence "projects.blender.org/studio/flamenco/internal/manager/persistence"
|
||||||
|
sqlc "projects.blender.org/studio/flamenco/internal/manager/persistence/sqlc"
|
||||||
api "projects.blender.org/studio/flamenco/pkg/api"
|
api "projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ func (mr *MockPersistenceServiceMockRecorder) FetchWorkerSleepSchedule(arg0, arg
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveWorkerStatus mocks base method.
|
// SaveWorkerStatus mocks base method.
|
||||||
func (m *MockPersistenceService) SaveWorkerStatus(arg0 context.Context, arg1 *persistence.Worker) error {
|
func (m *MockPersistenceService) SaveWorkerStatus(arg0 context.Context, arg1 *sqlc.Worker) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "SaveWorkerStatus", arg0, arg1)
|
ret := m.ctrl.Call(m, "SaveWorkerStatus", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
|
@ -178,7 +178,7 @@ func (ss *SleepScheduler) updateWorkerStatus(
|
|||||||
IsLazy: false,
|
IsLazy: false,
|
||||||
Status: worker.StatusRequested,
|
Status: worker.StatusRequested,
|
||||||
},
|
},
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ func TestApplySleepSchedule(t *testing.T) {
|
|||||||
ss, mocks, ctx := testFixtures(t)
|
ss, mocks, ctx := testFixtures(t)
|
||||||
|
|
||||||
worker := persistence.Worker{
|
worker := persistence.Worker{
|
||||||
Model: persistence.Model{ID: 5},
|
ID: 5,
|
||||||
UUID: "74997de4-c530-4913-b89f-c489f14f7634",
|
UUID: "74997de4-c530-4913-b89f-c489f14f7634",
|
||||||
Status: api.WorkerStatusOffline,
|
Status: api.WorkerStatusOffline,
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ func TestApplySleepScheduleNoStatusChange(t *testing.T) {
|
|||||||
ss, mocks, ctx := testFixtures(t)
|
ss, mocks, ctx := testFixtures(t)
|
||||||
|
|
||||||
worker := persistence.Worker{
|
worker := persistence.Worker{
|
||||||
Model: persistence.Model{ID: 5},
|
ID: 5,
|
||||||
UUID: "74997de4-c530-4913-b89f-c489f14f7634",
|
UUID: "74997de4-c530-4913-b89f-c489f14f7634",
|
||||||
Status: api.WorkerStatusAsleep,
|
Status: api.WorkerStatusAsleep,
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
zerolog "github.com/rs/zerolog"
|
zerolog "github.com/rs/zerolog"
|
||||||
persistence "projects.blender.org/studio/flamenco/internal/manager/persistence"
|
persistence "projects.blender.org/studio/flamenco/internal/manager/persistence"
|
||||||
|
sqlc "projects.blender.org/studio/flamenco/internal/manager/persistence/sqlc"
|
||||||
api "projects.blender.org/studio/flamenco/pkg/api"
|
api "projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ func (mr *MockPersistenceServiceMockRecorder) FetchJobsInStatus(arg0 interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchTasksOfWorkerInStatus mocks base method.
|
// FetchTasksOfWorkerInStatus mocks base method.
|
||||||
func (m *MockPersistenceService) FetchTasksOfWorkerInStatus(arg0 context.Context, arg1 *persistence.Worker, arg2 api.TaskStatus) ([]*persistence.Task, error) {
|
func (m *MockPersistenceService) FetchTasksOfWorkerInStatus(arg0 context.Context, arg1 *sqlc.Worker, arg2 api.TaskStatus) ([]*persistence.Task, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchTasksOfWorkerInStatus", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "FetchTasksOfWorkerInStatus", arg0, arg1, arg2)
|
||||||
ret0, _ := ret[0].([]*persistence.Task)
|
ret0, _ := ret[0].([]*persistence.Task)
|
||||||
@ -94,7 +95,7 @@ func (mr *MockPersistenceServiceMockRecorder) FetchTasksOfWorkerInStatus(arg0, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchTasksOfWorkerInStatusOfJob mocks base method.
|
// FetchTasksOfWorkerInStatusOfJob mocks base method.
|
||||||
func (m *MockPersistenceService) FetchTasksOfWorkerInStatusOfJob(arg0 context.Context, arg1 *persistence.Worker, arg2 api.TaskStatus, arg3 *persistence.Job) ([]*persistence.Task, error) {
|
func (m *MockPersistenceService) FetchTasksOfWorkerInStatusOfJob(arg0 context.Context, arg1 *sqlc.Worker, arg2 api.TaskStatus, arg3 *persistence.Job) ([]*persistence.Task, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchTasksOfWorkerInStatusOfJob", arg0, arg1, arg2, arg3)
|
ret := m.ctrl.Call(m, "FetchTasksOfWorkerInStatusOfJob", arg0, arg1, arg2, arg3)
|
||||||
ret0, _ := ret[0].([]*persistence.Task)
|
ret0, _ := ret[0].([]*persistence.Task)
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"projects.blender.org/studio/flamenco/internal/manager/eventbus"
|
"projects.blender.org/studio/flamenco/internal/manager/eventbus"
|
||||||
"projects.blender.org/studio/flamenco/internal/manager/persistence"
|
"projects.blender.org/studio/flamenco/internal/manager/persistence"
|
||||||
|
"projects.blender.org/studio/flamenco/internal/manager/persistence/sqlc"
|
||||||
"projects.blender.org/studio/flamenco/internal/manager/task_state_machine"
|
"projects.blender.org/studio/flamenco/internal/manager/task_state_machine"
|
||||||
"projects.blender.org/studio/flamenco/pkg/api"
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
@ -19,7 +20,7 @@ import (
|
|||||||
type PersistenceService interface {
|
type PersistenceService interface {
|
||||||
FetchTimedOutTasks(ctx context.Context, untouchedSince time.Time) ([]*persistence.Task, error)
|
FetchTimedOutTasks(ctx context.Context, untouchedSince time.Time) ([]*persistence.Task, error)
|
||||||
FetchTimedOutWorkers(ctx context.Context, lastSeenBefore time.Time) ([]*persistence.Worker, error)
|
FetchTimedOutWorkers(ctx context.Context, lastSeenBefore time.Time) ([]*persistence.Worker, error)
|
||||||
SaveWorker(ctx context.Context, w *persistence.Worker) error
|
SaveWorker(ctx context.Context, w *sqlc.Worker) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ PersistenceService = (*persistence.DB)(nil)
|
var _ PersistenceService = (*persistence.DB)(nil)
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
zerolog "github.com/rs/zerolog"
|
zerolog "github.com/rs/zerolog"
|
||||||
persistence "projects.blender.org/studio/flamenco/internal/manager/persistence"
|
persistence "projects.blender.org/studio/flamenco/internal/manager/persistence"
|
||||||
|
sqlc "projects.blender.org/studio/flamenco/internal/manager/persistence/sqlc"
|
||||||
api "projects.blender.org/studio/flamenco/pkg/api"
|
api "projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,10 +55,10 @@ func (mr *MockPersistenceServiceMockRecorder) FetchTimedOutTasks(arg0, arg1 inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchTimedOutWorkers mocks base method.
|
// FetchTimedOutWorkers mocks base method.
|
||||||
func (m *MockPersistenceService) FetchTimedOutWorkers(arg0 context.Context, arg1 time.Time) ([]*persistence.Worker, error) {
|
func (m *MockPersistenceService) FetchTimedOutWorkers(arg0 context.Context, arg1 time.Time) ([]*sqlc.Worker, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FetchTimedOutWorkers", arg0, arg1)
|
ret := m.ctrl.Call(m, "FetchTimedOutWorkers", arg0, arg1)
|
||||||
ret0, _ := ret[0].([]*persistence.Worker)
|
ret0, _ := ret[0].([]*sqlc.Worker)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
@ -69,7 +70,7 @@ func (mr *MockPersistenceServiceMockRecorder) FetchTimedOutWorkers(arg0, arg1 in
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveWorker mocks base method.
|
// SaveWorker mocks base method.
|
||||||
func (m *MockPersistenceService) SaveWorker(arg0 context.Context, arg1 *persistence.Worker) error {
|
func (m *MockPersistenceService) SaveWorker(arg0 context.Context, arg1 *sqlc.Worker) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "SaveWorker", arg0, arg1)
|
ret := m.ctrl.Call(m, "SaveWorker", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
@ -106,7 +107,7 @@ func (m *MockTaskStateMachine) EXPECT() *MockTaskStateMachineMockRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequeueActiveTasksOfWorker mocks base method.
|
// RequeueActiveTasksOfWorker mocks base method.
|
||||||
func (m *MockTaskStateMachine) RequeueActiveTasksOfWorker(arg0 context.Context, arg1 *persistence.Worker, arg2 string) error {
|
func (m *MockTaskStateMachine) RequeueActiveTasksOfWorker(arg0 context.Context, arg1 *sqlc.Worker, arg2 string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "RequeueActiveTasksOfWorker", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "RequeueActiveTasksOfWorker", arg0, arg1, arg2)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
|
@ -113,7 +113,7 @@ func TestTaskTimeout(t *testing.T) {
|
|||||||
worker := persistence.Worker{
|
worker := persistence.Worker{
|
||||||
UUID: "WORKER-UUID",
|
UUID: "WORKER-UUID",
|
||||||
Name: "Tester",
|
Name: "Tester",
|
||||||
Model: persistence.Model{ID: 47},
|
ID: 47,
|
||||||
}
|
}
|
||||||
taskUnassigned := persistence.Task{
|
taskUnassigned := persistence.Task{
|
||||||
UUID: "TASK-UUID-UNASSIGNED",
|
UUID: "TASK-UUID-UNASSIGNED",
|
||||||
@ -124,13 +124,13 @@ func TestTaskTimeout(t *testing.T) {
|
|||||||
UUID: "TASK-UUID-UNKNOWN",
|
UUID: "TASK-UUID-UNKNOWN",
|
||||||
Job: &job,
|
Job: &job,
|
||||||
LastTouchedAt: lastTime,
|
LastTouchedAt: lastTime,
|
||||||
WorkerID: &worker.ID,
|
WorkerID: ptr(uint(worker.ID)),
|
||||||
}
|
}
|
||||||
taskAssigned := persistence.Task{
|
taskAssigned := persistence.Task{
|
||||||
UUID: "TASK-UUID-ASSIGNED",
|
UUID: "TASK-UUID-ASSIGNED",
|
||||||
Job: &job,
|
Job: &job,
|
||||||
LastTouchedAt: lastTime,
|
LastTouchedAt: lastTime,
|
||||||
WorkerID: &worker.ID,
|
WorkerID: ptr(uint(worker.ID)),
|
||||||
Worker: &worker,
|
Worker: &worker,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"projects.blender.org/studio/flamenco/internal/manager/persistence"
|
"projects.blender.org/studio/flamenco/internal/manager/persistence/sqlc"
|
||||||
"projects.blender.org/studio/flamenco/pkg/api"
|
"projects.blender.org/studio/flamenco/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,11 +37,11 @@ func (ttc *TimeoutChecker) checkWorkers(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// timeoutTask marks a task as 'failed' due to a timeout.
|
// timeoutTask marks a task as 'failed' due to a timeout.
|
||||||
func (ttc *TimeoutChecker) timeoutWorker(ctx context.Context, worker *persistence.Worker) {
|
func (ttc *TimeoutChecker) timeoutWorker(ctx context.Context, worker *sqlc.Worker) {
|
||||||
logger := log.With().
|
logger := log.With().
|
||||||
Str("worker", worker.UUID).
|
Str("worker", worker.UUID).
|
||||||
Str("name", worker.Name).
|
Str("name", worker.Name).
|
||||||
Str("lastSeenAt", worker.LastSeenAt.String()).
|
Str("lastSeenAt", worker.LastSeenAt.Time.String()).
|
||||||
Logger()
|
Logger()
|
||||||
logger.Warn().Msg("TimeoutChecker: worker timed out")
|
logger.Warn().Msg("TimeoutChecker: worker timed out")
|
||||||
|
|
||||||
@ -63,9 +63,13 @@ func (ttc *TimeoutChecker) timeoutWorker(ctx context.Context, worker *persistenc
|
|||||||
ttc.broadcaster.BroadcastWorkerUpdate(api.EventWorkerUpdate{
|
ttc.broadcaster.BroadcastWorkerUpdate(api.EventWorkerUpdate{
|
||||||
Id: worker.UUID,
|
Id: worker.UUID,
|
||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
PreviousStatus: &prevStatus,
|
PreviousStatus: ptr(api.WorkerStatus(prevStatus)),
|
||||||
Status: api.WorkerStatusError,
|
Status: api.WorkerStatusError,
|
||||||
Updated: worker.UpdatedAt,
|
Updated: worker.UpdatedAt.Time,
|
||||||
Version: worker.Software,
|
Version: worker.Software,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ptr[T any](value T) *T {
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package timeout_checker
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -30,8 +31,8 @@ func TestWorkerTimeout(t *testing.T) {
|
|||||||
worker := persistence.Worker{
|
worker := persistence.Worker{
|
||||||
UUID: "WORKER-UUID",
|
UUID: "WORKER-UUID",
|
||||||
Name: "Tester",
|
Name: "Tester",
|
||||||
Model: persistence.Model{ID: 47},
|
ID: 47,
|
||||||
LastSeenAt: lastSeenAt,
|
LastSeenAt: sql.NullTime{Time: lastSeenAt, Valid: true},
|
||||||
Status: api.WorkerStatusAsleep,
|
Status: api.WorkerStatusAsleep,
|
||||||
StatusRequested: api.WorkerStatusAwake,
|
StatusRequested: api.WorkerStatusAwake,
|
||||||
}
|
}
|
||||||
@ -58,7 +59,7 @@ func TestWorkerTimeout(t *testing.T) {
|
|||||||
Name: worker.Name,
|
Name: worker.Name,
|
||||||
PreviousStatus: &prevStatus,
|
PreviousStatus: &prevStatus,
|
||||||
Status: api.WorkerStatusError,
|
Status: api.WorkerStatusError,
|
||||||
Updated: persistedWorker.UpdatedAt,
|
Updated: persistedWorker.UpdatedAt.Time,
|
||||||
Version: persistedWorker.Software,
|
Version: persistedWorker.Software,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
32
sqlc.yaml
32
sqlc.yaml
@ -11,6 +11,14 @@ sql:
|
|||||||
go_type:
|
go_type:
|
||||||
import: "encoding/json"
|
import: "encoding/json"
|
||||||
type: "RawMessage"
|
type: "RawMessage"
|
||||||
|
- column: jobs.status
|
||||||
|
go_type: { type: "JobStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: tasks.status
|
||||||
|
go_type: { type: "TaskStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status_requested
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
rename:
|
rename:
|
||||||
uuid: "UUID"
|
uuid: "UUID"
|
||||||
uuids: "UUIDs"
|
uuids: "UUIDs"
|
||||||
@ -28,6 +36,14 @@ sql:
|
|||||||
go_type:
|
go_type:
|
||||||
import: "encoding/json"
|
import: "encoding/json"
|
||||||
type: "RawMessage"
|
type: "RawMessage"
|
||||||
|
- column: jobs.status
|
||||||
|
go_type: { type: "JobStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: tasks.status
|
||||||
|
go_type: { type: "TaskStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status_requested
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
rename:
|
rename:
|
||||||
uuid: "UUID"
|
uuid: "UUID"
|
||||||
uuids: "UUIDs"
|
uuids: "UUIDs"
|
||||||
@ -45,6 +61,14 @@ sql:
|
|||||||
go_type:
|
go_type:
|
||||||
import: "encoding/json"
|
import: "encoding/json"
|
||||||
type: "RawMessage"
|
type: "RawMessage"
|
||||||
|
- column: jobs.status
|
||||||
|
go_type: { type: "JobStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: tasks.status
|
||||||
|
go_type: { type: "TaskStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status_requested
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
rename:
|
rename:
|
||||||
uuid: "UUID"
|
uuid: "UUID"
|
||||||
uuids: "UUIDs"
|
uuids: "UUIDs"
|
||||||
@ -62,6 +86,14 @@ sql:
|
|||||||
go_type:
|
go_type:
|
||||||
import: "encoding/json"
|
import: "encoding/json"
|
||||||
type: "RawMessage"
|
type: "RawMessage"
|
||||||
|
- column: jobs.status
|
||||||
|
go_type: { type: "JobStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: tasks.status
|
||||||
|
go_type: { type: "TaskStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
|
- column: workers.status_requested
|
||||||
|
go_type: { type: "WorkerStatus", import: "projects.blender.org/studio/flamenco/pkg/api" }
|
||||||
rename:
|
rename:
|
||||||
uuid: "UUID"
|
uuid: "UUID"
|
||||||
uuids: "UUIDs"
|
uuids: "UUIDs"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user