diff --git a/cmd/task/main.go b/cmd/task/main.go index d7853699eacdd6406531057c77fe0b3c8670c9c7..d65bbc215762363852ff9b0e50f28c81a478e1e6 100644 --- a/cmd/task/main.go +++ b/cmd/task/main.go @@ -107,7 +107,7 @@ func main() { ) { taskSvc = task.New(storage, storage, cache, logger) - taskListSvc = tasklist.New(storage, storage, logger) + taskListSvc = tasklist.New(storage, storage, cache, logger) healthSvc = health.New() } diff --git a/design/design.go b/design/design.go index 19bce998ec88c06dcd99234fa87b4ca34afb399f..5d00d67e622e655271d7c4e1bb42298d64077604 100644 --- a/design/design.go +++ b/design/design.go @@ -71,6 +71,25 @@ var _ = Service("taskList", func() { Response(StatusOK) }) }) + + Method("TaskListStatus", func() { + Description("TaskListStatus retrieves a taskList status containing all tasks' unique IDs and statuses from the Cache service.") + Payload(TaskListStatusRequest) + Result(TaskListStatusResponse) + HTTP(func() { + GET("/v1/taskListStatus/{taskListID}") + Response(StatusOK) + Response(StatusCreated, func() { + Tag("status", "created") + }) + Response(StatusAccepted, func() { + Tag("status", "pending") + }) + Response(StatusMultiStatus, func() { + Tag("status", "failed") + }) + }) + }) }) var _ = Service("health", func() { diff --git a/design/types.go b/design/types.go index 7178a145f82034751203139cd631fcca56bdbf0d..963958847a65f58e0ee6773e3f452cfec2ada48d 100644 --- a/design/types.go +++ b/design/types.go @@ -33,3 +33,38 @@ var CreateTaskListResult = Type("CreateTaskListResult", func() { Field(1, "taskListID", String, "Unique taskList identifier.") Required("taskListID") }) + +var TaskListStatusRequest = Type("TaskListStatusRequest", func() { + Field(1, "taskListID", String, "Unique taskList identifier.") + Required("taskListID") +}) + +var TaskListStatusResponse = Type("TaskListStatusResponse", func() { + Field(1, "id", String, "Unique taskList identifier.", func() { + Example("9cc9f504-2b7f-4e24-ac59-653e9533840a") + }) + Field(2, "status", String, "Current status of the taskList", func() { + Example("done") + }) + Field(3, "groups", ArrayOf(GroupStatus), "Array of GroupStatus") + Required("id", "status") +}) + +var GroupStatus = Type("GroupStatus", func() { + Field(1, "id", String, "Unique group identifier.", func() { + Example("a7d1349d-34b5-4c65-b671-d1aa362fc446") + }) + Field(2, "status", String, "Current status of the group", func() { + Example("done") + }) + Field(3, "tasks", ArrayOf(TaskStatus), "Array of TaskStatus") +}) + +var TaskStatus = Type("TaskStatus", func() { + Field(1, "id", String, "Unique task identifier.", func() { + Example("d16996cd-1977-42a9-90b2-b4548a35c1b4") + }) + Field(2, "status", String, "Current status of the task", func() { + Example("done") + }) +}) diff --git a/docs/task-list.md b/docs/task-list.md index 5b2b4fcf9e170d9923132004f31ebbb840d56376..93fc8a0b8475373535265df05c3bc5fe28b05000 100644 --- a/docs/task-list.md +++ b/docs/task-list.md @@ -55,9 +55,70 @@ an input to the next. If one task fails to execute, all following tasks are mark - Parallel group execution: tasks within the group are executed in parallel and the results are dependant. If a task fails to execute, this does not affect the other tasks but the group is marked with failed status. +### Task list State + The state of the task list asynchronous execution is available later on the `result` endpoint: ```shell -curl -v -X GET http://localhost:8082/v1/taskListResult/{taskListID} +curl -v -X GET http://localhost:8082/v1/taskListStatus/{taskListID} +``` +The state is returned as an HTTP status code. +- Status code `200` for `Done` state; +- Status code `201` for `Created` state; +- Status code `202` for `Pending` state (the task list is being executed); +- Status code `207` for `Failed` state (at least one task within the task list has failed). + +Example responses: + +HTTP Response code `200`: Done +```json +{ + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "done", + "groups": [ + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "type": "sequential", + "status": "done", + "tasks": [ + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "done" + }, + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "done" + } + ] + } + ] +} + +``` + +HTTP Response code `207`: Failed +```json +{ + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "failed", + "groups": [ + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "type": "sequential", + "status": "failed", + "tasks": [ + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "done" + }, + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "failed" + } + ] + } + ] +} + ``` ### Task list Executor Configuration diff --git a/gen/http/cli/task/cli.go b/gen/http/cli/task/cli.go index e125d9bae7407f0fabda3324cb9c3d1966b29ed4..7d8da6e65411a28f6f6ea2a9baa0b2e99fae75d0 100644 --- a/gen/http/cli/task/cli.go +++ b/gen/http/cli/task/cli.go @@ -27,15 +27,15 @@ import ( func UsageCommands() string { return `health (liveness|readiness) task (create|task-result) -task-list create +task-list (create|task-list-status) ` } // UsageExamples produces an example of a valid invocation of the CLI tool. func UsageExamples() string { return os.Args[0] + ` health liveness` + "\n" + - os.Args[0] + ` task create --body "Ipsam et est accusantium." --task-name "Corrupti quia autem dolorum sunt aperiam quaerat." --cache-namespace "Eveniet et eligendi sint quibusdam quia maxime." --cache-scope "Et ipsa voluptate."` + "\n" + - os.Args[0] + ` task-list create --body "Rerum quod error est esse nisi." --task-list-name "Sapiente et." --cache-namespace "Delectus natus eos." --cache-scope "Quae ut dolores ab."` + "\n" + + os.Args[0] + ` task create --body "Vel odio et doloribus est quod laborum." --task-name "Eveniet et eligendi sint quibusdam quia maxime." --cache-namespace "Et ipsa voluptate." --cache-scope "Quo qui fuga impedit eos fuga et."` + "\n" + + os.Args[0] + ` task-list create --body "Quaerat ut fugit voluptatem dolores deserunt in." --task-list-name "Delectus natus eos." --cache-namespace "Quae ut dolores ab." --cache-scope "Omnis commodi reiciendis eum non."` + "\n" + "" } @@ -73,6 +73,9 @@ func ParseEndpoint( taskListCreateTaskListNameFlag = taskListCreateFlags.String("task-list-name", "REQUIRED", "TaskList name.") taskListCreateCacheNamespaceFlag = taskListCreateFlags.String("cache-namespace", "", "") taskListCreateCacheScopeFlag = taskListCreateFlags.String("cache-scope", "", "") + + taskListTaskListStatusFlags = flag.NewFlagSet("task-list-status", flag.ExitOnError) + taskListTaskListStatusTaskListIDFlag = taskListTaskListStatusFlags.String("task-list-id", "REQUIRED", "Unique taskList identifier.") ) healthFlags.Usage = healthUsage healthLivenessFlags.Usage = healthLivenessUsage @@ -84,6 +87,7 @@ func ParseEndpoint( taskListFlags.Usage = taskListUsage taskListCreateFlags.Usage = taskListCreateUsage + taskListTaskListStatusFlags.Usage = taskListTaskListStatusUsage if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { return nil, nil, err @@ -146,6 +150,9 @@ func ParseEndpoint( case "create": epf = taskListCreateFlags + case "task-list-status": + epf = taskListTaskListStatusFlags + } } @@ -194,6 +201,9 @@ func ParseEndpoint( case "create": endpoint = c.Create() data, err = tasklistc.BuildCreatePayload(*taskListCreateBodyFlag, *taskListCreateTaskListNameFlag, *taskListCreateCacheNamespaceFlag, *taskListCreateCacheScopeFlag) + case "task-list-status": + endpoint = c.TaskListStatus() + data, err = tasklistc.BuildTaskListStatusPayload(*taskListTaskListStatusTaskListIDFlag) } } } @@ -262,7 +272,7 @@ Create a task and put it in a queue for execution. -cache-scope STRING: Example: - %[1]s task create --body "Ipsam et est accusantium." --task-name "Corrupti quia autem dolorum sunt aperiam quaerat." --cache-namespace "Eveniet et eligendi sint quibusdam quia maxime." --cache-scope "Et ipsa voluptate." + %[1]s task create --body "Vel odio et doloribus est quod laborum." --task-name "Eveniet et eligendi sint quibusdam quia maxime." --cache-namespace "Et ipsa voluptate." --cache-scope "Quo qui fuga impedit eos fuga et." `, os.Args[0]) } @@ -273,7 +283,7 @@ TaskResult retrieves task result from the Cache service. -task-id STRING: Unique task identifier. Example: - %[1]s task task-result --task-id "Excepturi aut consequatur animi rerum." + %[1]s task task-result --task-id "Dolores atque error ab." `, os.Args[0]) } @@ -285,7 +295,8 @@ Usage: %[1]s [globalflags] task-list COMMAND [flags] COMMAND: - create: Create a task list, corresponding groups and tasks and put them in respective queues for execution. + create: Create a task list and corresponding tasks and put them in respective queues for execution. + task-list-status: TaskListStatus retrieves a taskList status containing all tasks' unique IDs and statuses from the Cache service. Additional help: %[1]s task-list COMMAND --help @@ -294,13 +305,24 @@ Additional help: func taskListCreateUsage() { fmt.Fprintf(os.Stderr, `%[1]s [flags] task-list create -body JSON -task-list-name STRING -cache-namespace STRING -cache-scope STRING -Create a task list, corresponding groups and tasks and put them in respective queues for execution. +Create a task list and corresponding tasks and put them in respective queues for execution. -body JSON: -task-list-name STRING: TaskList name. -cache-namespace STRING: -cache-scope STRING: Example: - %[1]s task-list create --body "Rerum quod error est esse nisi." --task-list-name "Sapiente et." --cache-namespace "Delectus natus eos." --cache-scope "Quae ut dolores ab." + %[1]s task-list create --body "Quaerat ut fugit voluptatem dolores deserunt in." --task-list-name "Delectus natus eos." --cache-namespace "Quae ut dolores ab." --cache-scope "Omnis commodi reiciendis eum non." +`, os.Args[0]) +} + +func taskListTaskListStatusUsage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] task-list task-list-status -task-list-id STRING + +TaskListStatus retrieves a taskList status containing all tasks' unique IDs and statuses from the Cache service. + -task-list-id STRING: Unique taskList identifier. + +Example: + %[1]s task-list task-list-status --task-list-id "Deserunt dolor et autem quidem fugiat sint." `, os.Args[0]) } diff --git a/gen/http/openapi.json b/gen/http/openapi.json index 13e4956be85c69bb6664de4204a7dfbcf60f9db0..601af302016673200a7a0a9579f49f0f789ffbf7 100644 --- a/gen/http/openapi.json +++ b/gen/http/openapi.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":""},"host":"localhost:8082","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","required":false,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","required":false,"type":"string"},{"name":"any","in":"body","description":"Data contains JSON payload that will be used for task execution.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskCreateResponseBody","required":["taskID"]}}},"schemes":["http"]}},"/v1/taskList/{taskListName}":{"post":{"tags":["taskList"],"summary":"Create taskList","description":"Create a task list, corresponding groups and tasks and put them in respective queues for execution.","operationId":"taskList#Create","parameters":[{"name":"taskListName","in":"path","description":"TaskList name.","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","required":false,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","required":false,"type":"string"},{"name":"any","in":"body","description":"Data contains JSON payload that will be used for taskList execution.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskListCreateResponseBody","required":["taskListID"]}}},"schemes":["http"]}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}},"definitions":{"TaskCreateResponseBody":{"title":"TaskCreateResponseBody","type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Et officiis aut."}},"example":{"taskID":"Atque veritatis."},"required":["taskID"]},"TaskListCreateResponseBody":{"title":"TaskListCreateResponseBody","type":"object","properties":{"taskListID":{"type":"string","description":"Unique taskList identifier.","example":"Deserunt dolor et autem quidem fugiat sint."}},"example":{"taskListID":"Aut voluptas possimus quia aliquam sit."},"required":["taskListID"]}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":""},"host":"localhost:8082","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}},"schemes":["http"]}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","required":false,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","required":false,"type":"string"},{"name":"any","in":"body","description":"Data contains JSON payload that will be used for task execution.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskCreateResponseBody","required":["taskID"]}}},"schemes":["http"]}},"/v1/taskList/{taskListName}":{"post":{"tags":["taskList"],"summary":"Create taskList","description":"Create a task list and corresponding tasks and put them in respective queues for execution.","operationId":"taskList#Create","parameters":[{"name":"taskListName","in":"path","description":"TaskList name.","required":true,"type":"string"},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","required":false,"type":"string"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","required":false,"type":"string"},{"name":"any","in":"body","description":"Data contains JSON payload that will be used for taskList execution.","required":true,"schema":{"type":"string","format":"binary"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskListCreateResponseBody","required":["taskListID"]}}},"schemes":["http"]}},"/v1/taskListStatus/{taskListID}":{"get":{"tags":["taskList"],"summary":"TaskListStatus taskList","description":"TaskListStatus retrieves a taskList status containing all tasks' unique IDs and statuses from the Cache service.","operationId":"taskList#TaskListStatus","parameters":[{"name":"taskListID","in":"path","description":"Unique taskList identifier.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/TaskListTaskListStatusOKResponseBody","required":["id","status"]}},"201":{"description":"Created response.","schema":{"$ref":"#/definitions/TaskListTaskListStatusCreatedResponseBody","required":["id","status"]}},"202":{"description":"Accepted response.","schema":{"$ref":"#/definitions/TaskListTaskListStatusAcceptedResponseBody","required":["id","status"]}},"207":{"description":"Multi-Status response.","schema":{"$ref":"#/definitions/TaskListTaskListStatusMultiStatusResponseBody","required":["id","status"]}}},"schemes":["http"]}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"string","format":"binary"}}},"schemes":["http"]}}},"definitions":{"GroupStatusResponseBody":{"title":"GroupStatusResponseBody","type":"object","properties":{"id":{"type":"string","description":"Unique group identifier.","example":"a7d1349d-34b5-4c65-b671-d1aa362fc446"},"status":{"type":"string","description":"Current status of the group","example":"done"},"tasks":{"type":"array","items":{"$ref":"#/definitions/TaskStatusResponseBody"},"description":"Array of TaskStatus","example":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}},"example":{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}},"TaskCreateResponseBody":{"title":"TaskCreateResponseBody","type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Sit asperiores."}},"example":{"taskID":"Iste suscipit exercitationem facilis distinctio asperiores ut."},"required":["taskID"]},"TaskListCreateResponseBody":{"title":"TaskListCreateResponseBody","type":"object","properties":{"taskListID":{"type":"string","description":"Unique taskList identifier.","example":"Ducimus velit."}},"example":{"taskListID":"Et occaecati placeat."},"required":["taskListID"]},"TaskListTaskListStatusAcceptedResponseBody":{"title":"TaskListTaskListStatusAcceptedResponseBody","type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/definitions/GroupStatusResponseBody"},"description":"Array of GroupStatus","example":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}]},"id":{"type":"string","description":"Unique taskList identifier.","example":"9cc9f504-2b7f-4e24-ac59-653e9533840a"},"status":{"type":"string","description":"Current status of the taskList","example":"done"}},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"},"required":["id","status"]},"TaskListTaskListStatusCreatedResponseBody":{"title":"TaskListTaskListStatusCreatedResponseBody","type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/definitions/GroupStatusResponseBody"},"description":"Array of GroupStatus","example":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}]},"id":{"type":"string","description":"Unique taskList identifier.","example":"9cc9f504-2b7f-4e24-ac59-653e9533840a"},"status":{"type":"string","description":"Current status of the taskList","example":"done"}},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"},"required":["id","status"]},"TaskListTaskListStatusMultiStatusResponseBody":{"title":"TaskListTaskListStatusMultiStatusResponseBody","type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/definitions/GroupStatusResponseBody"},"description":"Array of GroupStatus","example":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}]},"id":{"type":"string","description":"Unique taskList identifier.","example":"9cc9f504-2b7f-4e24-ac59-653e9533840a"},"status":{"type":"string","description":"Current status of the taskList","example":"done"}},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"},"required":["id","status"]},"TaskListTaskListStatusOKResponseBody":{"title":"TaskListTaskListStatusOKResponseBody","type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/definitions/GroupStatusResponseBody"},"description":"Array of GroupStatus","example":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}]},"id":{"type":"string","description":"Unique taskList identifier.","example":"9cc9f504-2b7f-4e24-ac59-653e9533840a"},"status":{"type":"string","description":"Current status of the taskList","example":"done"}},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"},"required":["id","status"]},"TaskStatusResponseBody":{"title":"TaskStatusResponseBody","type":"object","properties":{"id":{"type":"string","description":"Unique task identifier.","example":"d16996cd-1977-42a9-90b2-b4548a35c1b4"},"status":{"type":"string","description":"Current status of the task","example":"done"}},"example":{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}}}} \ No newline at end of file diff --git a/gen/http/openapi.yaml b/gen/http/openapi.yaml index b9008d5a089c97a647cc5fb22c831bd7c86a9d92..146c123cfe4b87233e515dd22263e68a0fbc2e3b 100644 --- a/gen/http/openapi.yaml +++ b/gen/http/openapi.yaml @@ -79,8 +79,8 @@ paths: tags: - taskList summary: Create taskList - description: Create a task list, corresponding groups and tasks and put them - in respective queues for execution. + description: Create a task list and corresponding tasks and put them in respective + queues for execution. operationId: taskList#Create parameters: - name: taskListName @@ -114,6 +114,51 @@ paths: - taskListID schemes: - http + /v1/taskListStatus/{taskListID}: + get: + tags: + - taskList + summary: TaskListStatus taskList + description: TaskListStatus retrieves a taskList status containing all tasks' + unique IDs and statuses from the Cache service. + operationId: taskList#TaskListStatus + parameters: + - name: taskListID + in: path + description: Unique taskList identifier. + required: true + type: string + responses: + "200": + description: OK response. + schema: + $ref: '#/definitions/TaskListTaskListStatusOKResponseBody' + required: + - id + - status + "201": + description: Created response. + schema: + $ref: '#/definitions/TaskListTaskListStatusCreatedResponseBody' + required: + - id + - status + "202": + description: Accepted response. + schema: + $ref: '#/definitions/TaskListTaskListStatusAcceptedResponseBody' + required: + - id + - status + "207": + description: Multi-Status response. + schema: + $ref: '#/definitions/TaskListTaskListStatusMultiStatusResponseBody' + required: + - id + - status + schemes: + - http /v1/taskResult/{taskID}: get: tags: @@ -136,6 +181,40 @@ paths: schemes: - http definitions: + GroupStatusResponseBody: + title: GroupStatusResponseBody + type: object + properties: + id: + type: string + description: Unique group identifier. + example: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: + type: string + description: Current status of the group + example: done + tasks: + type: array + items: + $ref: '#/definitions/TaskStatusResponseBody' + description: Array of TaskStatus + example: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + example: + id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done TaskCreateResponseBody: title: TaskCreateResponseBody type: object @@ -143,9 +222,9 @@ definitions: taskID: type: string description: Unique task identifier. - example: Et officiis aut. + example: Sit asperiores. example: - taskID: Atque veritatis. + taskID: Iste suscipit exercitationem facilis distinctio asperiores ut. required: - taskID TaskListCreateResponseBody: @@ -155,8 +234,303 @@ definitions: taskListID: type: string description: Unique taskList identifier. - example: Deserunt dolor et autem quidem fugiat sint. + example: Ducimus velit. example: - taskListID: Aut voluptas possimus quia aliquam sit. + taskListID: Et occaecati placeat. required: - taskListID + TaskListTaskListStatusAcceptedResponseBody: + title: TaskListTaskListStatusAcceptedResponseBody + type: object + properties: + groups: + type: array + items: + $ref: '#/definitions/GroupStatusResponseBody' + description: Array of GroupStatus + example: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: + type: string + description: Unique taskList identifier. + example: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: + type: string + description: Current status of the taskList + example: done + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + required: + - id + - status + TaskListTaskListStatusCreatedResponseBody: + title: TaskListTaskListStatusCreatedResponseBody + type: object + properties: + groups: + type: array + items: + $ref: '#/definitions/GroupStatusResponseBody' + description: Array of GroupStatus + example: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: + type: string + description: Unique taskList identifier. + example: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: + type: string + description: Current status of the taskList + example: done + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + required: + - id + - status + TaskListTaskListStatusMultiStatusResponseBody: + title: TaskListTaskListStatusMultiStatusResponseBody + type: object + properties: + groups: + type: array + items: + $ref: '#/definitions/GroupStatusResponseBody' + description: Array of GroupStatus + example: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: + type: string + description: Unique taskList identifier. + example: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: + type: string + description: Current status of the taskList + example: done + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + required: + - id + - status + TaskListTaskListStatusOKResponseBody: + title: TaskListTaskListStatusOKResponseBody + type: object + properties: + groups: + type: array + items: + $ref: '#/definitions/GroupStatusResponseBody' + description: Array of GroupStatus + example: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: + type: string + description: Unique taskList identifier. + example: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: + type: string + description: Current status of the taskList + example: done + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + required: + - id + - status + TaskStatusResponseBody: + title: TaskStatusResponseBody + type: object + properties: + id: + type: string + description: Unique task identifier. + example: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: + type: string + description: Current status of the task + example: done + example: + id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done diff --git a/gen/http/openapi3.json b/gen/http/openapi3.json index 4a39db1b50f4e6ac9185165a43d3ae6c3b14c9f6..8f5099289b24b762f05dc73a122416f2638d3d9e 100644 --- a/gen/http/openapi3.json +++ b/gen/http/openapi3.json @@ -1 +1 @@ -{"openapi":"3.0.3","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":"1.0"},"servers":[{"url":"http://localhost:8082","description":"Task Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"schema":{"type":"string","description":"Task name.","example":"Voluptatem iure qui facilis aut."},"example":"Excepturi non."},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key namespace","example":"login"},"example":"login"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key scope","example":"user"},"example":"user"}],"requestBody":{"description":"Data contains JSON payload that will be used for task execution.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Data contains JSON payload that will be used for task execution.","example":"Impedit iste suscipit.","format":"binary"},"example":"Excepturi in ex ratione."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskResult"},"example":{"taskID":"Vel odio et doloribus est quod laborum."}}}}}}},"/v1/taskList/{taskListName}":{"post":{"tags":["taskList"],"summary":"Create taskList","description":"Create a task list, corresponding groups and tasks and put them in respective queues for execution.","operationId":"taskList#Create","parameters":[{"name":"taskListName","in":"path","description":"TaskList name.","required":true,"schema":{"type":"string","description":"TaskList name.","example":"Incidunt autem eaque."},"example":"Fugit ut eius sint earum."},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key namespace","example":"login"},"example":"login"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key scope","example":"user"},"example":"user"}],"requestBody":{"description":"Data contains JSON payload that will be used for taskList execution.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Data contains JSON payload that will be used for taskList execution.","example":"Reiciendis numquam.","format":"binary"},"example":"At consequatur nulla praesentium totam dolores voluptas."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskListResult"},"example":{"taskListID":"Quaerat ut fugit voluptatem dolores deserunt in."}}}}}}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"schema":{"type":"string","description":"Unique task identifier.","example":"Ut et est aut quae magnam."},"example":"Amet sapiente qui non."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Placeat molestias praesentium necessitatibus sed.","format":"binary"},"example":"Sint nulla."}}}}}}},"components":{"schemas":{"CreateTaskListResult":{"type":"object","properties":{"taskListID":{"type":"string","description":"Unique taskList identifier.","example":"Doloribus ullam voluptas quos aut tempore."}},"example":{"taskListID":"Porro perspiciatis qui vitae totam eligendi officiis."},"required":["taskListID"]},"CreateTaskResult":{"type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Facilis distinctio asperiores ut architecto ducimus."}},"example":{"taskID":"Omnis et."},"required":["taskID"]}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"task","description":"Task service provides endpoints to work with tasks."},{"name":"taskList","description":"TaskList service provides endpoints to work with task lists."}]} \ No newline at end of file +{"openapi":"3.0.3","info":{"title":"Task Service","description":"The task service is executing tasks created from policies.","version":"1.0"},"servers":[{"url":"http://localhost:8082","description":"Task Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/task/{taskName}":{"post":{"tags":["task"],"summary":"Create task","description":"Create a task and put it in a queue for execution.","operationId":"task#Create","parameters":[{"name":"taskName","in":"path","description":"Task name.","required":true,"schema":{"type":"string","description":"Task name.","example":"Voluptas laudantium incidunt autem eaque."},"example":"Fugit ut eius sint earum."},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key namespace","example":"login"},"example":"login"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key scope","example":"user"},"example":"user"}],"requestBody":{"description":"Data contains JSON payload that will be used for task execution.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Data contains JSON payload that will be used for task execution.","example":"Quos aut tempore enim porro.","format":"binary"},"example":"Consequatur nulla praesentium totam."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskResult"},"example":{"taskID":"Harum aut autem aliquam dolorem non soluta."}}}}}}},"/v1/taskList/{taskListName}":{"post":{"tags":["taskList"],"summary":"Create taskList","description":"Create a task list and corresponding tasks and put them in respective queues for execution.","operationId":"taskList#Create","parameters":[{"name":"taskListName","in":"path","description":"TaskList name.","required":true,"schema":{"type":"string","description":"TaskList name.","example":"Earum laborum accusamus id nihil."},"example":"Est eveniet dolores."},{"name":"x-cache-namespace","in":"header","description":"Cache key namespace","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key namespace","example":"login"},"example":"login"},{"name":"x-cache-scope","in":"header","description":"Cache key scope","allowEmptyValue":true,"schema":{"type":"string","description":"Cache key scope","example":"user"},"example":"user"}],"requestBody":{"description":"Data contains JSON payload that will be used for taskList execution.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Data contains JSON payload that will be used for taskList execution.","example":"Excepturi non.","format":"binary"},"example":"Laboriosam cumque."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTaskListResult"},"example":{"taskListID":"Et officiis aut."}}}}}}},"/v1/taskListStatus/{taskListID}":{"get":{"tags":["taskList"],"summary":"TaskListStatus taskList","description":"TaskListStatus retrieves a taskList status containing all tasks' unique IDs and statuses from the Cache service.","operationId":"taskList#TaskListStatus","parameters":[{"name":"taskListID","in":"path","description":"Unique taskList identifier.","required":true,"schema":{"type":"string","description":"Unique taskList identifier.","example":"Omnis optio magni sunt aliquid et."},"example":"Dignissimos doloribus rerum occaecati quia ut."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListStatusResponse"},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"}}}},"201":{"description":"Created response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListStatusResponse"},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"}}}},"202":{"description":"Accepted response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListStatusResponse"},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"}}}},"207":{"description":"Multi-Status response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaskListStatusResponse"},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"}}}}}}},"/v1/taskResult/{taskID}":{"get":{"tags":["task"],"summary":"TaskResult task","description":"TaskResult retrieves task result from the Cache service.","operationId":"task#TaskResult","parameters":[{"name":"taskID","in":"path","description":"Unique task identifier.","required":true,"schema":{"type":"string","description":"Unique task identifier.","example":"Doloremque earum aliquid ipsa."},"example":"Voluptas odit voluptate nobis nam quia quae."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Voluptatem iure qui facilis aut.","format":"binary"},"example":"Maxime facilis."}}}}}}},"components":{"schemas":{"CreateTaskListResult":{"type":"object","properties":{"taskListID":{"type":"string","description":"Unique taskList identifier.","example":"Ut et est aut quae magnam."}},"example":{"taskListID":"Amet sapiente qui non."},"required":["taskListID"]},"CreateTaskResult":{"type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Qui vitae."}},"example":{"taskID":"Eligendi officiis repudiandae excepturi in ex ratione."},"required":["taskID"]},"GroupStatus":{"type":"object","properties":{"id":{"type":"string","description":"Unique group identifier.","example":"a7d1349d-34b5-4c65-b671-d1aa362fc446"},"status":{"type":"string","description":"Current status of the group","example":"done"},"tasks":{"type":"array","items":{"$ref":"#/components/schemas/TaskStatus"},"description":"Array of TaskStatus","example":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}},"example":{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}},"TaskListStatusResponse":{"type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/components/schemas/GroupStatus"},"description":"Array of GroupStatus","example":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}]},"id":{"type":"string","description":"Unique taskList identifier.","example":"9cc9f504-2b7f-4e24-ac59-653e9533840a"},"status":{"type":"string","description":"Current status of the taskList","example":"done"}},"example":{"groups":[{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]},{"id":"a7d1349d-34b5-4c65-b671-d1aa362fc446","status":"done","tasks":[{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"},{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}]}],"id":"9cc9f504-2b7f-4e24-ac59-653e9533840a","status":"done"},"required":["id","status"]},"TaskStatus":{"type":"object","properties":{"id":{"type":"string","description":"Unique task identifier.","example":"d16996cd-1977-42a9-90b2-b4548a35c1b4"},"status":{"type":"string","description":"Current status of the task","example":"done"}},"example":{"id":"d16996cd-1977-42a9-90b2-b4548a35c1b4","status":"done"}}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"task","description":"Task service provides endpoints to work with tasks."},{"name":"taskList","description":"TaskList service provides endpoints to work with task lists."}]} \ No newline at end of file diff --git a/gen/http/openapi3.yaml b/gen/http/openapi3.yaml index 3b234d0b2694c25ae7b41a466c4a52329a6b48d7..d17d648965ac3f2296118f7339a9e6572e5acc30 100644 --- a/gen/http/openapi3.yaml +++ b/gen/http/openapi3.yaml @@ -40,8 +40,8 @@ paths: schema: type: string description: Task name. - example: Voluptatem iure qui facilis aut. - example: Excepturi non. + example: Voluptas laudantium incidunt autem eaque. + example: Fugit ut eius sint earum. - name: x-cache-namespace in: header description: Cache key namespace @@ -68,9 +68,9 @@ paths: schema: type: string description: Data contains JSON payload that will be used for task execution. - example: Impedit iste suscipit. + example: Quos aut tempore enim porro. format: binary - example: Excepturi in ex ratione. + example: Consequatur nulla praesentium totam. responses: "200": description: OK response. @@ -79,14 +79,14 @@ paths: schema: $ref: '#/components/schemas/CreateTaskResult' example: - taskID: Vel odio et doloribus est quod laborum. + taskID: Harum aut autem aliquam dolorem non soluta. /v1/taskList/{taskListName}: post: tags: - taskList summary: Create taskList - description: Create a task list, corresponding groups and tasks and put them - in respective queues for execution. + description: Create a task list and corresponding tasks and put them in respective + queues for execution. operationId: taskList#Create parameters: - name: taskListName @@ -96,8 +96,8 @@ paths: schema: type: string description: TaskList name. - example: Incidunt autem eaque. - example: Fugit ut eius sint earum. + example: Earum laborum accusamus id nihil. + example: Est eveniet dolores. - name: x-cache-namespace in: header description: Cache key namespace @@ -125,9 +125,9 @@ paths: type: string description: Data contains JSON payload that will be used for taskList execution. - example: Reiciendis numquam. + example: Excepturi non. format: binary - example: At consequatur nulla praesentium totam dolores voluptas. + example: Laboriosam cumque. responses: "200": description: OK response. @@ -136,7 +136,174 @@ paths: schema: $ref: '#/components/schemas/CreateTaskListResult' example: - taskListID: Quaerat ut fugit voluptatem dolores deserunt in. + taskListID: Et officiis aut. + /v1/taskListStatus/{taskListID}: + get: + tags: + - taskList + summary: TaskListStatus taskList + description: TaskListStatus retrieves a taskList status containing all tasks' + unique IDs and statuses from the Cache service. + operationId: taskList#TaskListStatus + parameters: + - name: taskListID + in: path + description: Unique taskList identifier. + required: true + schema: + type: string + description: Unique taskList identifier. + example: Omnis optio magni sunt aliquid et. + example: Dignissimos doloribus rerum occaecati quia ut. + responses: + "200": + description: OK response. + content: + application/json: + schema: + $ref: '#/components/schemas/TaskListStatusResponse' + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + "201": + description: Created response. + content: + application/json: + schema: + $ref: '#/components/schemas/TaskListStatusResponse' + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + "202": + description: Accepted response. + content: + application/json: + schema: + $ref: '#/components/schemas/TaskListStatusResponse' + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + "207": + description: Multi-Status response. + content: + application/json: + schema: + $ref: '#/components/schemas/TaskListStatusResponse' + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done /v1/taskResult/{taskID}: get: tags: @@ -152,8 +319,8 @@ paths: schema: type: string description: Unique task identifier. - example: Ut et est aut quae magnam. - example: Amet sapiente qui non. + example: Doloremque earum aliquid ipsa. + example: Voluptas odit voluptate nobis nam quia quae. responses: "200": description: OK response. @@ -161,9 +328,9 @@ paths: application/json: schema: type: string - example: Placeat molestias praesentium necessitatibus sed. + example: Voluptatem iure qui facilis aut. format: binary - example: Sint nulla. + example: Maxime facilis. components: schemas: CreateTaskListResult: @@ -172,9 +339,9 @@ components: taskListID: type: string description: Unique taskList identifier. - example: Doloribus ullam voluptas quos aut tempore. + example: Ut et est aut quae magnam. example: - taskListID: Porro perspiciatis qui vitae totam eligendi officiis. + taskListID: Amet sapiente qui non. required: - taskListID CreateTaskResult: @@ -183,11 +350,147 @@ components: taskID: type: string description: Unique task identifier. - example: Facilis distinctio asperiores ut architecto ducimus. + example: Qui vitae. example: - taskID: Omnis et. + taskID: Eligendi officiis repudiandae excepturi in ex ratione. required: - taskID + GroupStatus: + type: object + properties: + id: + type: string + description: Unique group identifier. + example: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: + type: string + description: Current status of the group + example: done + tasks: + type: array + items: + $ref: '#/components/schemas/TaskStatus' + description: Array of TaskStatus + example: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + example: + id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + TaskListStatusResponse: + type: object + properties: + groups: + type: array + items: + $ref: '#/components/schemas/GroupStatus' + description: Array of GroupStatus + example: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: + type: string + description: Unique taskList identifier. + example: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: + type: string + description: Current status of the taskList + example: done + example: + groups: + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: a7d1349d-34b5-4c65-b671-d1aa362fc446 + status: done + tasks: + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + - id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done + id: 9cc9f504-2b7f-4e24-ac59-653e9533840a + status: done + required: + - id + - status + TaskStatus: + type: object + properties: + id: + type: string + description: Unique task identifier. + example: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: + type: string + description: Current status of the task + example: done + example: + id: d16996cd-1977-42a9-90b2-b4548a35c1b4 + status: done tags: - name: health description: Health service provides health check endpoints. diff --git a/gen/http/task/client/cli.go b/gen/http/task/client/cli.go index 3080e4ebc945b6f4f29af532b072a18c0ad3094c..bf05073b6f41fa01db203999926e83d941fbe037 100644 --- a/gen/http/task/client/cli.go +++ b/gen/http/task/client/cli.go @@ -22,7 +22,7 @@ func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCr { err = json.Unmarshal([]byte(taskCreateBody), &body) if err != nil { - return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Ipsam et est accusantium.\"") + return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Vel odio et doloribus est quod laborum.\"") } } var taskName string diff --git a/gen/http/task_list/client/cli.go b/gen/http/task_list/client/cli.go index a46f7e6b65abf426b31ebafbdd65df0c52b216a8..b3449cf7f1e7114502127e44463c24429e85bbde 100644 --- a/gen/http/task_list/client/cli.go +++ b/gen/http/task_list/client/cli.go @@ -22,7 +22,7 @@ func BuildCreatePayload(taskListCreateBody string, taskListCreateTaskListName st { err = json.Unmarshal([]byte(taskListCreateBody), &body) if err != nil { - return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Rerum quod error est esse nisi.\"") + return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Quaerat ut fugit voluptatem dolores deserunt in.\"") } } var taskListName string @@ -51,3 +51,16 @@ func BuildCreatePayload(taskListCreateBody string, taskListCreateTaskListName st return res, nil } + +// BuildTaskListStatusPayload builds the payload for the taskList +// TaskListStatus endpoint from CLI flags. +func BuildTaskListStatusPayload(taskListTaskListStatusTaskListID string) (*tasklist.TaskListStatusRequest, error) { + var taskListID string + { + taskListID = taskListTaskListStatusTaskListID + } + v := &tasklist.TaskListStatusRequest{} + v.TaskListID = taskListID + + return v, nil +} diff --git a/gen/http/task_list/client/client.go b/gen/http/task_list/client/client.go index 7beb029b37d637bc6fc7ca2249ee7a84e2d100fe..4bc5df02bd6e9419c971ea460c57ca3f1d1d2324 100644 --- a/gen/http/task_list/client/client.go +++ b/gen/http/task_list/client/client.go @@ -20,6 +20,10 @@ type Client struct { // Create Doer is the HTTP client used to make requests to the Create endpoint. CreateDoer goahttp.Doer + // TaskListStatus Doer is the HTTP client used to make requests to the + // TaskListStatus endpoint. + TaskListStatusDoer goahttp.Doer + // RestoreResponseBody controls whether the response bodies are reset after // decoding so they can be read again. RestoreResponseBody bool @@ -41,6 +45,7 @@ func NewClient( ) *Client { return &Client{ CreateDoer: doer, + TaskListStatusDoer: doer, RestoreResponseBody: restoreBody, scheme: scheme, host: host, @@ -72,3 +77,22 @@ func (c *Client) Create() goa.Endpoint { return decodeResponse(resp) } } + +// TaskListStatus returns an endpoint that makes HTTP requests to the taskList +// service TaskListStatus server. +func (c *Client) TaskListStatus() goa.Endpoint { + var ( + decodeResponse = DecodeTaskListStatusResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v interface{}) (interface{}, error) { + req, err := c.BuildTaskListStatusRequest(ctx, v) + if err != nil { + return nil, err + } + resp, err := c.TaskListStatusDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("taskList", "TaskListStatus", err) + } + return decodeResponse(resp) + } +} diff --git a/gen/http/task_list/client/encode_decode.go b/gen/http/task_list/client/encode_decode.go index a8c5892c07ad6acdd709ff1f6875b1138eba762a..7f5bc119a002da0c6476876d47d7020e3d26acee 100644 --- a/gen/http/task_list/client/encode_decode.go +++ b/gen/http/task_list/client/encode_decode.go @@ -106,3 +106,150 @@ func DecodeCreateResponse(decoder func(*http.Response) goahttp.Decoder, restoreB } } } + +// BuildTaskListStatusRequest instantiates a HTTP request object with method +// and path set to call the "taskList" service "TaskListStatus" endpoint +func (c *Client) BuildTaskListStatusRequest(ctx context.Context, v interface{}) (*http.Request, error) { + var ( + taskListID string + ) + { + p, ok := v.(*tasklist.TaskListStatusRequest) + if !ok { + return nil, goahttp.ErrInvalidType("taskList", "TaskListStatus", "*tasklist.TaskListStatusRequest", v) + } + taskListID = p.TaskListID + } + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: TaskListStatusTaskListPath(taskListID)} + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("taskList", "TaskListStatus", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// DecodeTaskListStatusResponse returns a decoder for responses returned by the +// taskList TaskListStatus endpoint. restoreBody controls whether the response +// body should be restored after having been read. +func DecodeTaskListStatusResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (interface{}, error) { + return func(resp *http.Response) (interface{}, error) { + if restoreBody { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusMultiStatus: + var ( + body TaskListStatusMultiStatusResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("taskList", "TaskListStatus", err) + } + err = ValidateTaskListStatusMultiStatusResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("taskList", "TaskListStatus", err) + } + res := NewTaskListStatusResponseMultiStatus(&body) + res.Status = "failed" + return res, nil + case http.StatusCreated: + var ( + body TaskListStatusCreatedResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("taskList", "TaskListStatus", err) + } + err = ValidateTaskListStatusCreatedResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("taskList", "TaskListStatus", err) + } + res := NewTaskListStatusResponseCreated(&body) + res.Status = "created" + return res, nil + case http.StatusAccepted: + var ( + body TaskListStatusAcceptedResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("taskList", "TaskListStatus", err) + } + err = ValidateTaskListStatusAcceptedResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("taskList", "TaskListStatus", err) + } + res := NewTaskListStatusResponseAccepted(&body) + res.Status = "pending" + return res, nil + case http.StatusOK: + var ( + body TaskListStatusOKResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("taskList", "TaskListStatus", err) + } + err = ValidateTaskListStatusOKResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("taskList", "TaskListStatus", err) + } + res := NewTaskListStatusResponseOK(&body) + return res, nil + default: + body, _ := ioutil.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("taskList", "TaskListStatus", resp.StatusCode, string(body)) + } + } +} + +// unmarshalGroupStatusResponseBodyToTasklistGroupStatus builds a value of type +// *tasklist.GroupStatus from a value of type *GroupStatusResponseBody. +func unmarshalGroupStatusResponseBodyToTasklistGroupStatus(v *GroupStatusResponseBody) *tasklist.GroupStatus { + if v == nil { + return nil + } + res := &tasklist.GroupStatus{ + ID: v.ID, + Status: v.Status, + } + if v.Tasks != nil { + res.Tasks = make([]*tasklist.TaskStatus, len(v.Tasks)) + for i, val := range v.Tasks { + res.Tasks[i] = unmarshalTaskStatusResponseBodyToTasklistTaskStatus(val) + } + } + + return res +} + +// unmarshalTaskStatusResponseBodyToTasklistTaskStatus builds a value of type +// *tasklist.TaskStatus from a value of type *TaskStatusResponseBody. +func unmarshalTaskStatusResponseBodyToTasklistTaskStatus(v *TaskStatusResponseBody) *tasklist.TaskStatus { + if v == nil { + return nil + } + res := &tasklist.TaskStatus{ + ID: v.ID, + Status: v.Status, + } + + return res +} diff --git a/gen/http/task_list/client/paths.go b/gen/http/task_list/client/paths.go index ce764600818ffe4a5a0df13ee8cdd75e3db92428..1409e86fb538f04ee09088fc8b2a9430b0ca2dcb 100644 --- a/gen/http/task_list/client/paths.go +++ b/gen/http/task_list/client/paths.go @@ -15,3 +15,8 @@ import ( func CreateTaskListPath(taskListName string) string { return fmt.Sprintf("/v1/taskList/%v", taskListName) } + +// TaskListStatusTaskListPath returns the URL path to the taskList service TaskListStatus HTTP endpoint. +func TaskListStatusTaskListPath(taskListID string) string { + return fmt.Sprintf("/v1/taskListStatus/%v", taskListID) +} diff --git a/gen/http/task_list/client/types.go b/gen/http/task_list/client/types.go index 902273026c2e1b2237fc0b70252f96669b7e42c1..6233bd9199aa079cb82b1d931482e7931dd6eb24 100644 --- a/gen/http/task_list/client/types.go +++ b/gen/http/task_list/client/types.go @@ -19,6 +19,68 @@ type CreateResponseBody struct { TaskListID *string `form:"taskListID,omitempty" json:"taskListID,omitempty" xml:"taskListID,omitempty"` } +// TaskListStatusMultiStatusResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusMultiStatusResponseBody struct { + // Unique taskList identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the taskList + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// TaskListStatusCreatedResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusCreatedResponseBody struct { + // Unique taskList identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the taskList + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// TaskListStatusAcceptedResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusAcceptedResponseBody struct { + // Unique taskList identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the taskList + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// TaskListStatusOKResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusOKResponseBody struct { + // Unique taskList identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the taskList + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// GroupStatusResponseBody is used to define fields on response body types. +type GroupStatusResponseBody struct { + // Unique group identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the group + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` + // Array of TaskStatus + Tasks []*TaskStatusResponseBody `form:"tasks,omitempty" json:"tasks,omitempty" xml:"tasks,omitempty"` +} + +// TaskStatusResponseBody is used to define fields on response body types. +type TaskStatusResponseBody struct { + // Unique task identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the task + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` +} + // NewCreateTaskListResultOK builds a "taskList" service "Create" endpoint // result from a HTTP "OK" response. func NewCreateTaskListResultOK(body *CreateResponseBody) *tasklist.CreateTaskListResult { @@ -29,6 +91,74 @@ func NewCreateTaskListResultOK(body *CreateResponseBody) *tasklist.CreateTaskLis return v } +// NewTaskListStatusResponseMultiStatus builds a "taskList" service +// "TaskListStatus" endpoint result from a HTTP "MultiStatus" response. +func NewTaskListStatusResponseMultiStatus(body *TaskListStatusMultiStatusResponseBody) *tasklist.TaskListStatusResponse { + v := &tasklist.TaskListStatusResponse{ + ID: *body.ID, + Status: *body.Status, + } + if body.Groups != nil { + v.Groups = make([]*tasklist.GroupStatus, len(body.Groups)) + for i, val := range body.Groups { + v.Groups[i] = unmarshalGroupStatusResponseBodyToTasklistGroupStatus(val) + } + } + + return v +} + +// NewTaskListStatusResponseCreated builds a "taskList" service +// "TaskListStatus" endpoint result from a HTTP "Created" response. +func NewTaskListStatusResponseCreated(body *TaskListStatusCreatedResponseBody) *tasklist.TaskListStatusResponse { + v := &tasklist.TaskListStatusResponse{ + ID: *body.ID, + Status: *body.Status, + } + if body.Groups != nil { + v.Groups = make([]*tasklist.GroupStatus, len(body.Groups)) + for i, val := range body.Groups { + v.Groups[i] = unmarshalGroupStatusResponseBodyToTasklistGroupStatus(val) + } + } + + return v +} + +// NewTaskListStatusResponseAccepted builds a "taskList" service +// "TaskListStatus" endpoint result from a HTTP "Accepted" response. +func NewTaskListStatusResponseAccepted(body *TaskListStatusAcceptedResponseBody) *tasklist.TaskListStatusResponse { + v := &tasklist.TaskListStatusResponse{ + ID: *body.ID, + Status: *body.Status, + } + if body.Groups != nil { + v.Groups = make([]*tasklist.GroupStatus, len(body.Groups)) + for i, val := range body.Groups { + v.Groups[i] = unmarshalGroupStatusResponseBodyToTasklistGroupStatus(val) + } + } + + return v +} + +// NewTaskListStatusResponseOK builds a "taskList" service "TaskListStatus" +// endpoint result from a HTTP "OK" response. +func NewTaskListStatusResponseOK(body *TaskListStatusOKResponseBody) *tasklist.TaskListStatusResponse { + v := &tasklist.TaskListStatusResponse{ + ID: *body.ID, + Status: *body.Status, + } + if body.Groups != nil { + v.Groups = make([]*tasklist.GroupStatus, len(body.Groups)) + for i, val := range body.Groups { + v.Groups[i] = unmarshalGroupStatusResponseBodyToTasklistGroupStatus(val) + } + } + + return v +} + // ValidateCreateResponseBody runs the validations defined on CreateResponseBody func ValidateCreateResponseBody(body *CreateResponseBody) (err error) { if body.TaskListID == nil { @@ -36,3 +166,51 @@ func ValidateCreateResponseBody(body *CreateResponseBody) (err error) { } return } + +// ValidateTaskListStatusMultiStatusResponseBody runs the validations defined +// on TaskListStatusMulti-StatusResponseBody +func ValidateTaskListStatusMultiStatusResponseBody(body *TaskListStatusMultiStatusResponseBody) (err error) { + if body.ID == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) + } + if body.Status == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("status", "body")) + } + return +} + +// ValidateTaskListStatusCreatedResponseBody runs the validations defined on +// TaskListStatusCreatedResponseBody +func ValidateTaskListStatusCreatedResponseBody(body *TaskListStatusCreatedResponseBody) (err error) { + if body.ID == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) + } + if body.Status == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("status", "body")) + } + return +} + +// ValidateTaskListStatusAcceptedResponseBody runs the validations defined on +// TaskListStatusAcceptedResponseBody +func ValidateTaskListStatusAcceptedResponseBody(body *TaskListStatusAcceptedResponseBody) (err error) { + if body.ID == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) + } + if body.Status == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("status", "body")) + } + return +} + +// ValidateTaskListStatusOKResponseBody runs the validations defined on +// TaskListStatusOKResponseBody +func ValidateTaskListStatusOKResponseBody(body *TaskListStatusOKResponseBody) (err error) { + if body.ID == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("id", "body")) + } + if body.Status == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("status", "body")) + } + return +} diff --git a/gen/http/task_list/server/encode_decode.go b/gen/http/task_list/server/encode_decode.go index be27fbb71c3e3e8a5cfc1859b3aabb3352be4fab..20ca784942a5b088f13f737d28571dc7bc7954ab 100644 --- a/gen/http/task_list/server/encode_decode.go +++ b/gen/http/task_list/server/encode_decode.go @@ -66,3 +66,83 @@ func DecodeCreateRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp. return payload, nil } } + +// EncodeTaskListStatusResponse returns an encoder for responses returned by +// the taskList TaskListStatus endpoint. +func EncodeTaskListStatusResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error { + return func(ctx context.Context, w http.ResponseWriter, v interface{}) error { + res, _ := v.(*tasklist.TaskListStatusResponse) + if res.Status == "failed" { + enc := encoder(ctx, w) + body := NewTaskListStatusMultiStatusResponseBody(res) + w.WriteHeader(http.StatusMultiStatus) + return enc.Encode(body) + } + if res.Status == "created" { + enc := encoder(ctx, w) + body := NewTaskListStatusCreatedResponseBody(res) + w.WriteHeader(http.StatusCreated) + return enc.Encode(body) + } + if res.Status == "pending" { + enc := encoder(ctx, w) + body := NewTaskListStatusAcceptedResponseBody(res) + w.WriteHeader(http.StatusAccepted) + return enc.Encode(body) + } + enc := encoder(ctx, w) + body := NewTaskListStatusOKResponseBody(res) + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeTaskListStatusRequest returns a decoder for requests sent to the +// taskList TaskListStatus endpoint. +func DecodeTaskListStatusRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) { + return func(r *http.Request) (interface{}, error) { + var ( + taskListID string + + params = mux.Vars(r) + ) + taskListID = params["taskListID"] + payload := NewTaskListStatusRequest(taskListID) + + return payload, nil + } +} + +// marshalTasklistGroupStatusToGroupStatusResponseBody builds a value of type +// *GroupStatusResponseBody from a value of type *tasklist.GroupStatus. +func marshalTasklistGroupStatusToGroupStatusResponseBody(v *tasklist.GroupStatus) *GroupStatusResponseBody { + if v == nil { + return nil + } + res := &GroupStatusResponseBody{ + ID: v.ID, + Status: v.Status, + } + if v.Tasks != nil { + res.Tasks = make([]*TaskStatusResponseBody, len(v.Tasks)) + for i, val := range v.Tasks { + res.Tasks[i] = marshalTasklistTaskStatusToTaskStatusResponseBody(val) + } + } + + return res +} + +// marshalTasklistTaskStatusToTaskStatusResponseBody builds a value of type +// *TaskStatusResponseBody from a value of type *tasklist.TaskStatus. +func marshalTasklistTaskStatusToTaskStatusResponseBody(v *tasklist.TaskStatus) *TaskStatusResponseBody { + if v == nil { + return nil + } + res := &TaskStatusResponseBody{ + ID: v.ID, + Status: v.Status, + } + + return res +} diff --git a/gen/http/task_list/server/paths.go b/gen/http/task_list/server/paths.go index 80662ac5bb501534cf2f22138127b98eb86bcece..ccdd062b3b76273771d5a5cf5f2d0b68919884cf 100644 --- a/gen/http/task_list/server/paths.go +++ b/gen/http/task_list/server/paths.go @@ -15,3 +15,8 @@ import ( func CreateTaskListPath(taskListName string) string { return fmt.Sprintf("/v1/taskList/%v", taskListName) } + +// TaskListStatusTaskListPath returns the URL path to the taskList service TaskListStatus HTTP endpoint. +func TaskListStatusTaskListPath(taskListID string) string { + return fmt.Sprintf("/v1/taskListStatus/%v", taskListID) +} diff --git a/gen/http/task_list/server/server.go b/gen/http/task_list/server/server.go index 4d4d72dcec6b49130f5823ceb8148687eb4ccab0..648c3f3ead27c3fbba1576ad0868f9f49102529a 100644 --- a/gen/http/task_list/server/server.go +++ b/gen/http/task_list/server/server.go @@ -18,8 +18,9 @@ import ( // Server lists the taskList service endpoint HTTP handlers. type Server struct { - Mounts []*MountPoint - Create http.Handler + Mounts []*MountPoint + Create http.Handler + TaskListStatus http.Handler } // ErrorNamer is an interface implemented by generated error structs that @@ -56,8 +57,10 @@ func New( return &Server{ Mounts: []*MountPoint{ {"Create", "POST", "/v1/taskList/{taskListName}"}, + {"TaskListStatus", "GET", "/v1/taskListStatus/{taskListID}"}, }, - Create: NewCreateHandler(e.Create, mux, decoder, encoder, errhandler, formatter), + Create: NewCreateHandler(e.Create, mux, decoder, encoder, errhandler, formatter), + TaskListStatus: NewTaskListStatusHandler(e.TaskListStatus, mux, decoder, encoder, errhandler, formatter), } } @@ -67,11 +70,13 @@ func (s *Server) Service() string { return "taskList" } // Use wraps the server handlers with the given middleware. func (s *Server) Use(m func(http.Handler) http.Handler) { s.Create = m(s.Create) + s.TaskListStatus = m(s.TaskListStatus) } // Mount configures the mux to serve the taskList endpoints. func Mount(mux goahttp.Muxer, h *Server) { MountCreateHandler(mux, h.Create) + MountTaskListStatusHandler(mux, h.TaskListStatus) } // Mount configures the mux to serve the taskList endpoints. @@ -129,3 +134,54 @@ func NewCreateHandler( } }) } + +// MountTaskListStatusHandler configures the mux to serve the "taskList" +// service "TaskListStatus" endpoint. +func MountTaskListStatusHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("GET", "/v1/taskListStatus/{taskListID}", f) +} + +// NewTaskListStatusHandler creates a HTTP handler which loads the HTTP request +// and calls the "taskList" service "TaskListStatus" endpoint. +func NewTaskListStatusHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodeTaskListStatusRequest(mux, decoder) + encodeResponse = EncodeTaskListStatusResponse(encoder) + encodeError = goahttp.ErrorEncoder(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "TaskListStatus") + ctx = context.WithValue(ctx, goa.ServiceKey, "taskList") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + errhandler(ctx, w, err) + } + }) +} diff --git a/gen/http/task_list/server/types.go b/gen/http/task_list/server/types.go index 879b0a1fa38948d6d92357413004176b75adea8c..0bbdb6c9ffbb65ab7e17d51467755565e13bf190 100644 --- a/gen/http/task_list/server/types.go +++ b/gen/http/task_list/server/types.go @@ -18,6 +18,68 @@ type CreateResponseBody struct { TaskListID string `form:"taskListID" json:"taskListID" xml:"taskListID"` } +// TaskListStatusMultiStatusResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusMultiStatusResponseBody struct { + // Unique taskList identifier. + ID string `form:"id" json:"id" xml:"id"` + // Current status of the taskList + Status string `form:"status" json:"status" xml:"status"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// TaskListStatusCreatedResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusCreatedResponseBody struct { + // Unique taskList identifier. + ID string `form:"id" json:"id" xml:"id"` + // Current status of the taskList + Status string `form:"status" json:"status" xml:"status"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// TaskListStatusAcceptedResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusAcceptedResponseBody struct { + // Unique taskList identifier. + ID string `form:"id" json:"id" xml:"id"` + // Current status of the taskList + Status string `form:"status" json:"status" xml:"status"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// TaskListStatusOKResponseBody is the type of the "taskList" service +// "TaskListStatus" endpoint HTTP response body. +type TaskListStatusOKResponseBody struct { + // Unique taskList identifier. + ID string `form:"id" json:"id" xml:"id"` + // Current status of the taskList + Status string `form:"status" json:"status" xml:"status"` + // Array of GroupStatus + Groups []*GroupStatusResponseBody `form:"groups,omitempty" json:"groups,omitempty" xml:"groups,omitempty"` +} + +// GroupStatusResponseBody is used to define fields on response body types. +type GroupStatusResponseBody struct { + // Unique group identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the group + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` + // Array of TaskStatus + Tasks []*TaskStatusResponseBody `form:"tasks,omitempty" json:"tasks,omitempty" xml:"tasks,omitempty"` +} + +// TaskStatusResponseBody is used to define fields on response body types. +type TaskStatusResponseBody struct { + // Unique task identifier. + ID *string `form:"id,omitempty" json:"id,omitempty" xml:"id,omitempty"` + // Current status of the task + Status *string `form:"status,omitempty" json:"status,omitempty" xml:"status,omitempty"` +} + // NewCreateResponseBody builds the HTTP response body from the result of the // "Create" endpoint of the "taskList" service. func NewCreateResponseBody(res *tasklist.CreateTaskListResult) *CreateResponseBody { @@ -27,6 +89,70 @@ func NewCreateResponseBody(res *tasklist.CreateTaskListResult) *CreateResponseBo return body } +// NewTaskListStatusMultiStatusResponseBody builds the HTTP response body from +// the result of the "TaskListStatus" endpoint of the "taskList" service. +func NewTaskListStatusMultiStatusResponseBody(res *tasklist.TaskListStatusResponse) *TaskListStatusMultiStatusResponseBody { + body := &TaskListStatusMultiStatusResponseBody{ + ID: res.ID, + Status: res.Status, + } + if res.Groups != nil { + body.Groups = make([]*GroupStatusResponseBody, len(res.Groups)) + for i, val := range res.Groups { + body.Groups[i] = marshalTasklistGroupStatusToGroupStatusResponseBody(val) + } + } + return body +} + +// NewTaskListStatusCreatedResponseBody builds the HTTP response body from the +// result of the "TaskListStatus" endpoint of the "taskList" service. +func NewTaskListStatusCreatedResponseBody(res *tasklist.TaskListStatusResponse) *TaskListStatusCreatedResponseBody { + body := &TaskListStatusCreatedResponseBody{ + ID: res.ID, + Status: res.Status, + } + if res.Groups != nil { + body.Groups = make([]*GroupStatusResponseBody, len(res.Groups)) + for i, val := range res.Groups { + body.Groups[i] = marshalTasklistGroupStatusToGroupStatusResponseBody(val) + } + } + return body +} + +// NewTaskListStatusAcceptedResponseBody builds the HTTP response body from the +// result of the "TaskListStatus" endpoint of the "taskList" service. +func NewTaskListStatusAcceptedResponseBody(res *tasklist.TaskListStatusResponse) *TaskListStatusAcceptedResponseBody { + body := &TaskListStatusAcceptedResponseBody{ + ID: res.ID, + Status: res.Status, + } + if res.Groups != nil { + body.Groups = make([]*GroupStatusResponseBody, len(res.Groups)) + for i, val := range res.Groups { + body.Groups[i] = marshalTasklistGroupStatusToGroupStatusResponseBody(val) + } + } + return body +} + +// NewTaskListStatusOKResponseBody builds the HTTP response body from the +// result of the "TaskListStatus" endpoint of the "taskList" service. +func NewTaskListStatusOKResponseBody(res *tasklist.TaskListStatusResponse) *TaskListStatusOKResponseBody { + body := &TaskListStatusOKResponseBody{ + ID: res.ID, + Status: res.Status, + } + if res.Groups != nil { + body.Groups = make([]*GroupStatusResponseBody, len(res.Groups)) + for i, val := range res.Groups { + body.Groups[i] = marshalTasklistGroupStatusToGroupStatusResponseBody(val) + } + } + return body +} + // NewCreateTaskListRequest builds a taskList service Create endpoint payload. func NewCreateTaskListRequest(body interface{}, taskListName string, cacheNamespace *string, cacheScope *string) *tasklist.CreateTaskListRequest { v := body @@ -39,3 +165,12 @@ func NewCreateTaskListRequest(body interface{}, taskListName string, cacheNamesp return res } + +// NewTaskListStatusRequest builds a taskList service TaskListStatus endpoint +// payload. +func NewTaskListStatusRequest(taskListID string) *tasklist.TaskListStatusRequest { + v := &tasklist.TaskListStatusRequest{} + v.TaskListID = taskListID + + return v +} diff --git a/gen/task_list/client.go b/gen/task_list/client.go index dcaf4ef0bdab346d90e25b0f4773756a72c10f42..d877a52535b4c7ff6a6a8a8f5477b9d87bb34d96 100644 --- a/gen/task_list/client.go +++ b/gen/task_list/client.go @@ -15,13 +15,15 @@ import ( // Client is the "taskList" service client. type Client struct { - CreateEndpoint goa.Endpoint + CreateEndpoint goa.Endpoint + TaskListStatusEndpoint goa.Endpoint } // NewClient initializes a "taskList" service client given the endpoints. -func NewClient(create goa.Endpoint) *Client { +func NewClient(create, taskListStatus goa.Endpoint) *Client { return &Client{ - CreateEndpoint: create, + CreateEndpoint: create, + TaskListStatusEndpoint: taskListStatus, } } @@ -34,3 +36,13 @@ func (c *Client) Create(ctx context.Context, p *CreateTaskListRequest) (res *Cre } return ires.(*CreateTaskListResult), nil } + +// TaskListStatus calls the "TaskListStatus" endpoint of the "taskList" service. +func (c *Client) TaskListStatus(ctx context.Context, p *TaskListStatusRequest) (res *TaskListStatusResponse, err error) { + var ires interface{} + ires, err = c.TaskListStatusEndpoint(ctx, p) + if err != nil { + return + } + return ires.(*TaskListStatusResponse), nil +} diff --git a/gen/task_list/endpoints.go b/gen/task_list/endpoints.go index 0a2bc0e4b32a0704d6cf429df56fd1c5823cf708..98659ce6197c558b4a80e649eb887da4d3ee90df 100644 --- a/gen/task_list/endpoints.go +++ b/gen/task_list/endpoints.go @@ -15,19 +15,22 @@ import ( // Endpoints wraps the "taskList" service endpoints. type Endpoints struct { - Create goa.Endpoint + Create goa.Endpoint + TaskListStatus goa.Endpoint } // NewEndpoints wraps the methods of the "taskList" service with endpoints. func NewEndpoints(s Service) *Endpoints { return &Endpoints{ - Create: NewCreateEndpoint(s), + Create: NewCreateEndpoint(s), + TaskListStatus: NewTaskListStatusEndpoint(s), } } // Use applies the given middleware to all the "taskList" service endpoints. func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { e.Create = m(e.Create) + e.TaskListStatus = m(e.TaskListStatus) } // NewCreateEndpoint returns an endpoint function that calls the method @@ -38,3 +41,12 @@ func NewCreateEndpoint(s Service) goa.Endpoint { return s.Create(ctx, p) } } + +// NewTaskListStatusEndpoint returns an endpoint function that calls the method +// "TaskListStatus" of service "taskList". +func NewTaskListStatusEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req interface{}) (interface{}, error) { + p := req.(*TaskListStatusRequest) + return s.TaskListStatus(ctx, p) + } +} diff --git a/gen/task_list/service.go b/gen/task_list/service.go index e7dbf3ae62c41719450b9ba97002b00c184f3fce..3c82eda7634d6f616ff5315d4eae1fb862397157 100644 --- a/gen/task_list/service.go +++ b/gen/task_list/service.go @@ -13,9 +13,12 @@ import ( // TaskList service provides endpoints to work with task lists. type Service interface { - // Create a task list, corresponding groups and tasks and put them in - // respective queues for execution. + // Create a task list and corresponding tasks and put them in respective queues + // for execution. Create(context.Context, *CreateTaskListRequest) (res *CreateTaskListResult, err error) + // TaskListStatus retrieves a taskList status containing all tasks' unique IDs + // and statuses from the Cache service. + TaskListStatus(context.Context, *TaskListStatusRequest) (res *TaskListStatusResponse, err error) } // ServiceName is the name of the service as defined in the design. This is the @@ -26,7 +29,7 @@ const ServiceName = "taskList" // MethodNames lists the service method names as defined in the design. These // are the same values that are set in the endpoint request contexts under the // MethodKey key. -var MethodNames = [1]string{"Create"} +var MethodNames = [2]string{"Create", "TaskListStatus"} // CreateTaskListRequest is the payload type of the taskList service Create // method. @@ -47,3 +50,37 @@ type CreateTaskListResult struct { // Unique taskList identifier. TaskListID string } + +type GroupStatus struct { + // Unique group identifier. + ID *string + // Current status of the group + Status *string + // Array of TaskStatus + Tasks []*TaskStatus +} + +// TaskListStatusRequest is the payload type of the taskList service +// TaskListStatus method. +type TaskListStatusRequest struct { + // Unique taskList identifier. + TaskListID string +} + +// TaskListStatusResponse is the result type of the taskList service +// TaskListStatus method. +type TaskListStatusResponse struct { + // Unique taskList identifier. + ID string + // Current status of the taskList + Status string + // Array of GroupStatus + Groups []*GroupStatus +} + +type TaskStatus struct { + // Unique task identifier. + ID *string + // Current status of the task + Status *string +} diff --git a/internal/listexecutor/listexecutor.go b/internal/listexecutor/listexecutor.go index b05bad414c12af2880cfce1296ea5c4473bbe1eb..29615ad89a23598290f01e7b0e9055485d74e1a0 100644 --- a/internal/listexecutor/listexecutor.go +++ b/internal/listexecutor/listexecutor.go @@ -3,6 +3,7 @@ package listexecutor import ( "bytes" "context" + "encoding/json" "io" "net/http" "sync" @@ -11,6 +12,8 @@ import ( "go.uber.org/zap" "code.vereign.com/gaiax/tsa/golib/errors" + "code.vereign.com/gaiax/tsa/golib/ptr" + goatasklist "code.vereign.com/gaiax/tsa/task/gen/task_list" taskpkg "code.vereign.com/gaiax/tsa/task/internal/service/task" "code.vereign.com/gaiax/tsa/task/internal/service/tasklist" ) @@ -125,13 +128,17 @@ func (l *ListExecutor) Execute(ctx context.Context, list *tasklist.TaskList) { list.State = taskpkg.Pending list.StartedAt = time.Now() + var state goatasklist.TaskListStatusResponse + // execute groups sequentially for i := range list.Groups { - if err := l.executeGroup(ctx, &list.Groups[i]); err != nil { + groupState, err := l.executeGroup(ctx, &list.Groups[i]) + if err != nil { logger.Error("error executing group", zap.Error(err)) list.Groups[i].State = taskpkg.Failed list.State = taskpkg.Failed } + state.Groups = append(state.Groups, groupState) } if list.State != taskpkg.Failed { @@ -139,6 +146,20 @@ func (l *ListExecutor) Execute(ctx context.Context, list *tasklist.TaskList) { } list.FinishedAt = time.Now() + state.ID = list.ID + state.Status = string(list.State) + + value, err := json.Marshal(state) + if err != nil { + logger.Error("error marshaling taskList state", zap.Error(err)) + } else { + if err := l.cache.Set(ctx, list.ID, list.CacheNamespace, list.CacheScope, value); err != nil { + logger.Error("error storing taskList state in cache", zap.Error(err)) + } else { + logger.Debug("taskList state is stored in cache") + } + } + if err := l.storage.SaveTaskListHistory(ctx, list); err != nil { logger.Error("error saving taskList history", zap.Error(err)) } else { @@ -150,7 +171,7 @@ func (l *ListExecutor) Execute(ctx context.Context, list *tasklist.TaskList) { } } -func (l *ListExecutor) executeGroup(ctx context.Context, group *tasklist.Group) error { +func (l *ListExecutor) executeGroup(ctx context.Context, group *tasklist.Group) (*goatasklist.GroupStatus, error) { switch exec := group.Execution; exec { case sequential: return l.executeSequential(ctx, group) @@ -158,19 +179,22 @@ func (l *ListExecutor) executeGroup(ctx context.Context, group *tasklist.Group) return l.executeParallel(ctx, group) } - return errors.New("unknown type of group execution") + return nil, errors.New("unknown type of group execution") } -func (l *ListExecutor) executeSequential(ctx context.Context, group *tasklist.Group) error { +func (l *ListExecutor) executeSequential(ctx context.Context, group *tasklist.Group) (*goatasklist.GroupStatus, error) { group.State = taskpkg.Pending + var state goatasklist.GroupStatus tasks, err := l.storage.GetGroupTasks(ctx, group) if err != nil { - return err + return nil, err } req := group.Request for _, task := range tasks { + taskState := goatasklist.TaskStatus{ID: &task.ID} + logger := l.logger.With( zap.String("taskID", task.ID), zap.String("taskName", task.Name), @@ -179,6 +203,8 @@ func (l *ListExecutor) executeSequential(ctx context.Context, group *tasklist.Gr // mark all subsequent tasks as failed if one task already failed if group.State == taskpkg.Failed { task.State = taskpkg.Failed + taskState.Status = ptr.String(taskpkg.Failed) + state.Tasks = append(state.Tasks, &taskState) continue } @@ -186,12 +212,17 @@ func (l *ListExecutor) executeSequential(ctx context.Context, group *tasklist.Gr err := l.executeTask(ctx, task) if err != nil { task.State = taskpkg.Failed + taskState.Status = ptr.String(taskpkg.Failed) + state.Tasks = append(state.Tasks, &taskState) group.State = taskpkg.Failed logger.Error("error executing task", zap.Error(err)) continue } logger.Debug("task execution completed successfully") + taskState.Status = ptr.String(string(task.State)) + state.Tasks = append(state.Tasks, &taskState) + // pass the response from current task as an input to the next task req = task.Response @@ -223,21 +254,29 @@ func (l *ListExecutor) executeSequential(ctx context.Context, group *tasklist.Gr group.State = taskpkg.Done } - return nil + state.ID = &group.ID + state.Status = ptr.String(string(group.State)) + + return &state, nil } -func (l *ListExecutor) executeParallel(ctx context.Context, group *tasklist.Group) error { +func (l *ListExecutor) executeParallel(ctx context.Context, group *tasklist.Group) (*goatasklist.GroupStatus, error) { group.State = taskpkg.Pending + var state goatasklist.GroupStatus tasks, err := l.storage.GetGroupTasks(ctx, group) if err != nil { - return err + return nil, err } var wg sync.WaitGroup for _, task := range tasks { wg.Add(1) go func(t *taskpkg.Task) { + taskState := goatasklist.TaskStatus{ + ID: &t.ID, + } + defer wg.Done() logger := l.logger.With( zap.String("taskID", t.ID), @@ -248,12 +287,17 @@ func (l *ListExecutor) executeParallel(ctx context.Context, group *tasklist.Grou if err := l.executeTask(ctx, t); err != nil { t.State = taskpkg.Failed + taskState.Status = ptr.String(taskpkg.Failed) + state.Tasks = append(state.Tasks, &taskState) group.State = taskpkg.Failed logger.Error("error executing task", zap.Error(err)) return } logger.Debug("task execution completed successfully") + taskState.Status = ptr.String(string(t.State)) + state.Tasks = append(state.Tasks, &taskState) + if err := l.cache.Set( ctx, t.ID, @@ -286,7 +330,10 @@ func (l *ListExecutor) executeParallel(ctx context.Context, group *tasklist.Grou group.State = taskpkg.Done } - return nil + state.ID = &group.ID + state.Status = ptr.String(string(group.State)) + + return &state, nil } func (l *ListExecutor) executeTask(ctx context.Context, task *taskpkg.Task) error { diff --git a/internal/service/tasklist/service.go b/internal/service/tasklist/service.go index 5542a7d24eace9e0d4782eea171151a4a46b4603..2fc94f5d4131a4938d7cba593fe0a3ab9cfe5d6d 100644 --- a/internal/service/tasklist/service.go +++ b/internal/service/tasklist/service.go @@ -1,6 +1,7 @@ package tasklist import ( + "bytes" "context" "encoding/json" "time" @@ -9,34 +10,45 @@ import ( "go.uber.org/zap" "code.vereign.com/gaiax/tsa/golib/errors" + "code.vereign.com/gaiax/tsa/golib/ptr" goatasklist "code.vereign.com/gaiax/tsa/task/gen/task_list" "code.vereign.com/gaiax/tsa/task/internal/service/task" ) //go:generate counterfeiter . Storage //go:generate counterfeiter . Queue +//go:generate counterfeiter . Cache // Storage for retrieving predefined task templates. type Storage interface { TaskListTemplate(ctx context.Context, taskListName string) (*Template, error) TaskTemplates(ctx context.Context, names []string) (map[string]*task.Task, error) + TaskList(ctx context.Context, taskListID string) (*TaskList, error) + TaskListHistory(ctx context.Context, taskListID string) (*TaskList, error) + GetGroupTasks(ctx context.Context, group *Group) ([]*task.Task, error) } type Queue interface { AddTaskList(ctx context.Context, taskList *TaskList, tasks []*task.Task) error } +type Cache interface { + Get(ctx context.Context, key, namespace, scope string) ([]byte, error) +} + type Service struct { storage Storage queue Queue + cache Cache logger *zap.Logger } -func New(template Storage, queue Queue, logger *zap.Logger) *Service { +func New(template Storage, queue Queue, cache Cache, logger *zap.Logger) *Service { return &Service{ storage: template, queue: queue, + cache: cache, logger: logger, } } @@ -105,6 +117,59 @@ func (s *Service) Create(ctx context.Context, req *goatasklist.CreateTaskListReq }, nil } +// TaskListStatus retrieves a taskList result containing all tasks' unique IDs +// and statuses from the Cache service. +func (s *Service) TaskListStatus(ctx context.Context, req *goatasklist.TaskListStatusRequest) (res *goatasklist.TaskListStatusResponse, err error) { + if req.TaskListID == "" { + return nil, errors.New(errors.BadRequest, "missing taskListID") + } + + logger := s.logger.With(zap.String("taskListID", req.TaskListID)) + + var list *TaskList + list, err = s.storage.TaskListHistory(ctx, req.TaskListID) + if err != nil && !errors.Is(errors.NotFound, err) { + logger.Error("error getting taskList from history collection", zap.Error(err)) + return nil, err + } + + if list == nil { + list, err = s.storage.TaskList(ctx, req.TaskListID) + if err != nil { + if errors.Is(errors.NotFound, err) { + return nil, errors.New("taskList is not found", err) + } + logger.Error("error getting taskList from taskLists collection", zap.Error(err)) + return nil, err + } + } + + var result *goatasklist.TaskListStatusResponse + if list.State != task.Done && list.State != task.Failed { + // taskList is not executed yet + result, err = s.calculateState(ctx, list) + if err != nil { + logger.Error("error calculating taskList state", zap.Error(err)) + return nil, err + } + } else { + // taskList is already executed + var value []byte + value, err = s.cache.Get(ctx, list.ID, list.CacheNamespace, list.CacheScope) + if err != nil { + logger.Error("error getting taskList result from cache", zap.Error(err)) + return nil, err + } + + if err := json.NewDecoder(bytes.NewReader(value)).Decode(&result); err != nil { + logger.Error("error decoding result from cache", zap.Error(err)) + return nil, errors.New("error decoding result from cache", err) + } + } + + return result, nil +} + func createGroups(t *Template, req []byte) []Group { var groups []Group for _, group := range t.Groups { @@ -163,6 +228,36 @@ func createTasks(t *TaskList, templates map[string]*task.Task) ([]*task.Task, er return tasks, nil } +func (s *Service) calculateState(ctx context.Context, list *TaskList) (*goatasklist.TaskListStatusResponse, error) { + result := &goatasklist.TaskListStatusResponse{ + ID: list.ID, + Status: string(list.State), + } + + for i := range list.Groups { + groupState := goatasklist.GroupStatus{ + ID: &list.Groups[i].ID, + Status: ptr.String(string(list.Groups[i].State)), + } + + tasks, err := s.storage.GetGroupTasks(ctx, &list.Groups[i]) + if err != nil { + return nil, err + } + for j := range tasks { + taskState := goatasklist.TaskStatus{ + ID: &tasks[j].ID, + Status: ptr.String(string(tasks[j].State)), + } + groupState.Tasks = append(groupState.Tasks, &taskState) + } + + result.Groups = append(result.Groups, &groupState) + } + + return result, nil +} + // taskNamesFromTaskListTemplate returns the names of all tasks within // one taskList template func taskNamesFromTaskListTemplate(template *Template) []string { diff --git a/internal/service/tasklist/service_test.go b/internal/service/tasklist/service_test.go index 9dd3b39e39b25076f55f206661264627f2917c07..7e71903497891b26408f6876a134e4ab6d05a336 100644 --- a/internal/service/tasklist/service_test.go +++ b/internal/service/tasklist/service_test.go @@ -15,7 +15,7 @@ import ( ) func TestNew(t *testing.T) { - svc := tasklist.New(nil, nil, zap.NewNop()) + svc := tasklist.New(nil, nil, nil, zap.NewNop()) assert.Implements(t, (*goatasklist.Service)(nil), svc) } @@ -120,7 +120,7 @@ func Test_Create(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - svc := tasklist.New(test.storage, test.queue, zap.NewNop()) + svc := tasklist.New(test.storage, test.queue, nil, zap.NewNop()) res, err := svc.Create(context.Background(), test.req) if err != nil { assert.NotEmpty(t, test.errtext) @@ -138,3 +138,181 @@ func Test_Create(t *testing.T) { }) } } + +func Test_TaskListStatus(t *testing.T) { + tests := []struct { + name string + req *goatasklist.TaskListStatusRequest + storage *tasklistfakes.FakeStorage + queue *tasklistfakes.FakeQueue + cache *tasklistfakes.FakeCache + + errkind errors.Kind + errtext string + }{ + { + name: "missing taskList ID", + req: &goatasklist.TaskListStatusRequest{}, + errkind: errors.BadRequest, + errtext: "missing taskListID", + }, + { + name: "error getting taskList form history collection", + req: &goatasklist.TaskListStatusRequest{TaskListID: "d16996cd-1977-42a9-90b2-b4548a35c1b4"}, + storage: &tasklistfakes.FakeStorage{ + TaskListHistoryStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return nil, errors.New("some error") + }, + }, + errkind: errors.Unknown, + errtext: "some error", + }, + { + name: "taskList not found", + req: &goatasklist.TaskListStatusRequest{TaskListID: "d16996cd-1977-42a9-90b2-b4548a35c1b4"}, + storage: &tasklistfakes.FakeStorage{ + TaskListHistoryStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return nil, errors.New(errors.NotFound) + }, + TaskListStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return nil, errors.New(errors.NotFound) + }, + }, + errkind: errors.NotFound, + errtext: "taskList is not found", + }, + { + name: "error getting taskList from taskLists collection", + req: &goatasklist.TaskListStatusRequest{TaskListID: "d16996cd-1977-42a9-90b2-b4548a35c1b4"}, + storage: &tasklistfakes.FakeStorage{ + TaskListHistoryStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return nil, errors.New(errors.NotFound) + }, + TaskListStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return nil, errors.New("some error") + }, + }, + errkind: errors.Unknown, + errtext: "some error", + }, + { + name: "error calculating taskList state", + req: &goatasklist.TaskListStatusRequest{TaskListID: "d16996cd-1977-42a9-90b2-b4548a35c1b4"}, + storage: &tasklistfakes.FakeStorage{ + TaskListHistoryStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return pendingTaskList, nil + }, + GetGroupTasksStub: func(ctx context.Context, group *tasklist.Group) ([]*task.Task, error) { + return nil, errors.New("some error") + }, + }, + errkind: errors.Unknown, + errtext: "some error", + }, + { + name: "error getting taskList from cache", + req: &goatasklist.TaskListStatusRequest{TaskListID: "d16996cd-1977-42a9-90b2-b4548a35c1b4"}, + storage: &tasklistfakes.FakeStorage{ + TaskListHistoryStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return doneTaskList, nil + }, + }, + cache: &tasklistfakes.FakeCache{ + GetStub: func(ctx context.Context, key, namespace, scope string) ([]byte, error) { + return nil, errors.New("some cache error") + }, + }, + errkind: errors.Unknown, + errtext: "some cache error", + }, + { + name: "successfully get taskList state on pending task", + req: &goatasklist.TaskListStatusRequest{TaskListID: "d16996cd-1977-42a9-90b2-b4548a35c1b4"}, + storage: &tasklistfakes.FakeStorage{ + TaskListHistoryStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return pendingTaskList, nil + }, + GetGroupTasksStub: func(ctx context.Context, group *tasklist.Group) ([]*task.Task, error) { + return []*task.Task{}, nil + }, + }, + }, + { + name: "successfully get taskList state on executed task", + req: &goatasklist.TaskListStatusRequest{TaskListID: "d16996cd-1977-42a9-90b2-b4548a35c1b4"}, + storage: &tasklistfakes.FakeStorage{ + TaskListHistoryStub: func(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + return doneTaskList, nil + }, + }, + cache: &tasklistfakes.FakeCache{ + GetStub: func(ctx context.Context, key, namespace, scope string) ([]byte, error) { + return doneTaskState, nil + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + svc := tasklist.New(test.storage, test.queue, test.cache, zap.NewNop()) + res, err := svc.TaskListStatus(context.Background(), test.req) + if err != nil { + assert.NotEmpty(t, test.errtext) + e, ok := err.(*errors.Error) + assert.True(t, ok) + assert.Equal(t, test.errkind, e.Kind) + assert.Contains(t, e.Error(), test.errtext) + assert.Nil(t, res) + } else { + assert.Empty(t, test.errtext) + assert.NotNil(t, res) + assert.NotEmpty(t, res.ID) + assert.NotEmpty(t, res.Status) + assert.NotEmpty(t, res.Groups) + } + }) + } +} + +//nolint:gosec +var pendingTaskList = &tasklist.TaskList{ + ID: "16996cd-1977-42a9-90b2-b4548a35c1b4", + State: "pending", + Groups: []tasklist.Group{ + { + ID: "074076d5-c995-4d2d-8d38-da57360453d4", + Tasks: []string{"createdTask", "createdTask2"}, + State: "created", + }, + }, +} + +//nolint:gosec +var doneTaskList = &tasklist.TaskList{ + ID: "16996cd-1977-42a9-90b2-b4548a35c1b4", + State: "done", +} + +//nolint:gosec +var doneTaskState = []byte(`{ + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "done", + "groups": [ + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "type": "sequential", + "status": "done", + "tasks": [ + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "done" + }, + { + "id": "ad641603-1ca0-4342-ad73-d70a6b1ec502", + "status": "done" + } + ] + } + ] +}`) diff --git a/internal/service/tasklist/tasklistfakes/fake_cache.go b/internal/service/tasklist/tasklistfakes/fake_cache.go new file mode 100644 index 0000000000000000000000000000000000000000..2f636bdb059b5e8cc84bd827b91bbc65e67a8d37 --- /dev/null +++ b/internal/service/tasklist/tasklistfakes/fake_cache.go @@ -0,0 +1,123 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package tasklistfakes + +import ( + "context" + "sync" + + "code.vereign.com/gaiax/tsa/task/internal/service/tasklist" +) + +type FakeCache struct { + GetStub func(context.Context, string, string, string) ([]byte, error) + getMutex sync.RWMutex + getArgsForCall []struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + } + getReturns struct { + result1 []byte + result2 error + } + getReturnsOnCall map[int]struct { + result1 []byte + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeCache) Get(arg1 context.Context, arg2 string, arg3 string, arg4 string) ([]byte, error) { + fake.getMutex.Lock() + ret, specificReturn := fake.getReturnsOnCall[len(fake.getArgsForCall)] + fake.getArgsForCall = append(fake.getArgsForCall, struct { + arg1 context.Context + arg2 string + arg3 string + arg4 string + }{arg1, arg2, arg3, arg4}) + stub := fake.GetStub + fakeReturns := fake.getReturns + fake.recordInvocation("Get", []interface{}{arg1, arg2, arg3, arg4}) + fake.getMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeCache) GetCallCount() int { + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + return len(fake.getArgsForCall) +} + +func (fake *FakeCache) GetCalls(stub func(context.Context, string, string, string) ([]byte, error)) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = stub +} + +func (fake *FakeCache) GetArgsForCall(i int) (context.Context, string, string, string) { + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + argsForCall := fake.getArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 +} + +func (fake *FakeCache) GetReturns(result1 []byte, result2 error) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = nil + fake.getReturns = struct { + result1 []byte + result2 error + }{result1, result2} +} + +func (fake *FakeCache) GetReturnsOnCall(i int, result1 []byte, result2 error) { + fake.getMutex.Lock() + defer fake.getMutex.Unlock() + fake.GetStub = nil + if fake.getReturnsOnCall == nil { + fake.getReturnsOnCall = make(map[int]struct { + result1 []byte + result2 error + }) + } + fake.getReturnsOnCall[i] = struct { + result1 []byte + result2 error + }{result1, result2} +} + +func (fake *FakeCache) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.getMutex.RLock() + defer fake.getMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeCache) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ tasklist.Cache = new(FakeCache) diff --git a/internal/service/tasklist/tasklistfakes/fake_storage.go b/internal/service/tasklist/tasklistfakes/fake_storage.go index 9ece29b9180862d8281bd5759b4104ff9a731e67..4dd7cf097593ba40b96d8e9ea7731d96914d1a19 100644 --- a/internal/service/tasklist/tasklistfakes/fake_storage.go +++ b/internal/service/tasklist/tasklistfakes/fake_storage.go @@ -10,6 +10,48 @@ import ( ) type FakeStorage struct { + GetGroupTasksStub func(context.Context, *tasklist.Group) ([]*task.Task, error) + getGroupTasksMutex sync.RWMutex + getGroupTasksArgsForCall []struct { + arg1 context.Context + arg2 *tasklist.Group + } + getGroupTasksReturns struct { + result1 []*task.Task + result2 error + } + getGroupTasksReturnsOnCall map[int]struct { + result1 []*task.Task + result2 error + } + TaskListStub func(context.Context, string) (*tasklist.TaskList, error) + taskListMutex sync.RWMutex + taskListArgsForCall []struct { + arg1 context.Context + arg2 string + } + taskListReturns struct { + result1 *tasklist.TaskList + result2 error + } + taskListReturnsOnCall map[int]struct { + result1 *tasklist.TaskList + result2 error + } + TaskListHistoryStub func(context.Context, string) (*tasklist.TaskList, error) + taskListHistoryMutex sync.RWMutex + taskListHistoryArgsForCall []struct { + arg1 context.Context + arg2 string + } + taskListHistoryReturns struct { + result1 *tasklist.TaskList + result2 error + } + taskListHistoryReturnsOnCall map[int]struct { + result1 *tasklist.TaskList + result2 error + } TaskListTemplateStub func(context.Context, string) (*tasklist.Template, error) taskListTemplateMutex sync.RWMutex taskListTemplateArgsForCall []struct { @@ -42,6 +84,201 @@ type FakeStorage struct { invocationsMutex sync.RWMutex } +func (fake *FakeStorage) GetGroupTasks(arg1 context.Context, arg2 *tasklist.Group) ([]*task.Task, error) { + fake.getGroupTasksMutex.Lock() + ret, specificReturn := fake.getGroupTasksReturnsOnCall[len(fake.getGroupTasksArgsForCall)] + fake.getGroupTasksArgsForCall = append(fake.getGroupTasksArgsForCall, struct { + arg1 context.Context + arg2 *tasklist.Group + }{arg1, arg2}) + stub := fake.GetGroupTasksStub + fakeReturns := fake.getGroupTasksReturns + fake.recordInvocation("GetGroupTasks", []interface{}{arg1, arg2}) + fake.getGroupTasksMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeStorage) GetGroupTasksCallCount() int { + fake.getGroupTasksMutex.RLock() + defer fake.getGroupTasksMutex.RUnlock() + return len(fake.getGroupTasksArgsForCall) +} + +func (fake *FakeStorage) GetGroupTasksCalls(stub func(context.Context, *tasklist.Group) ([]*task.Task, error)) { + fake.getGroupTasksMutex.Lock() + defer fake.getGroupTasksMutex.Unlock() + fake.GetGroupTasksStub = stub +} + +func (fake *FakeStorage) GetGroupTasksArgsForCall(i int) (context.Context, *tasklist.Group) { + fake.getGroupTasksMutex.RLock() + defer fake.getGroupTasksMutex.RUnlock() + argsForCall := fake.getGroupTasksArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeStorage) GetGroupTasksReturns(result1 []*task.Task, result2 error) { + fake.getGroupTasksMutex.Lock() + defer fake.getGroupTasksMutex.Unlock() + fake.GetGroupTasksStub = nil + fake.getGroupTasksReturns = struct { + result1 []*task.Task + result2 error + }{result1, result2} +} + +func (fake *FakeStorage) GetGroupTasksReturnsOnCall(i int, result1 []*task.Task, result2 error) { + fake.getGroupTasksMutex.Lock() + defer fake.getGroupTasksMutex.Unlock() + fake.GetGroupTasksStub = nil + if fake.getGroupTasksReturnsOnCall == nil { + fake.getGroupTasksReturnsOnCall = make(map[int]struct { + result1 []*task.Task + result2 error + }) + } + fake.getGroupTasksReturnsOnCall[i] = struct { + result1 []*task.Task + result2 error + }{result1, result2} +} + +func (fake *FakeStorage) TaskList(arg1 context.Context, arg2 string) (*tasklist.TaskList, error) { + fake.taskListMutex.Lock() + ret, specificReturn := fake.taskListReturnsOnCall[len(fake.taskListArgsForCall)] + fake.taskListArgsForCall = append(fake.taskListArgsForCall, struct { + arg1 context.Context + arg2 string + }{arg1, arg2}) + stub := fake.TaskListStub + fakeReturns := fake.taskListReturns + fake.recordInvocation("TaskList", []interface{}{arg1, arg2}) + fake.taskListMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeStorage) TaskListCallCount() int { + fake.taskListMutex.RLock() + defer fake.taskListMutex.RUnlock() + return len(fake.taskListArgsForCall) +} + +func (fake *FakeStorage) TaskListCalls(stub func(context.Context, string) (*tasklist.TaskList, error)) { + fake.taskListMutex.Lock() + defer fake.taskListMutex.Unlock() + fake.TaskListStub = stub +} + +func (fake *FakeStorage) TaskListArgsForCall(i int) (context.Context, string) { + fake.taskListMutex.RLock() + defer fake.taskListMutex.RUnlock() + argsForCall := fake.taskListArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeStorage) TaskListReturns(result1 *tasklist.TaskList, result2 error) { + fake.taskListMutex.Lock() + defer fake.taskListMutex.Unlock() + fake.TaskListStub = nil + fake.taskListReturns = struct { + result1 *tasklist.TaskList + result2 error + }{result1, result2} +} + +func (fake *FakeStorage) TaskListReturnsOnCall(i int, result1 *tasklist.TaskList, result2 error) { + fake.taskListMutex.Lock() + defer fake.taskListMutex.Unlock() + fake.TaskListStub = nil + if fake.taskListReturnsOnCall == nil { + fake.taskListReturnsOnCall = make(map[int]struct { + result1 *tasklist.TaskList + result2 error + }) + } + fake.taskListReturnsOnCall[i] = struct { + result1 *tasklist.TaskList + result2 error + }{result1, result2} +} + +func (fake *FakeStorage) TaskListHistory(arg1 context.Context, arg2 string) (*tasklist.TaskList, error) { + fake.taskListHistoryMutex.Lock() + ret, specificReturn := fake.taskListHistoryReturnsOnCall[len(fake.taskListHistoryArgsForCall)] + fake.taskListHistoryArgsForCall = append(fake.taskListHistoryArgsForCall, struct { + arg1 context.Context + arg2 string + }{arg1, arg2}) + stub := fake.TaskListHistoryStub + fakeReturns := fake.taskListHistoryReturns + fake.recordInvocation("TaskListHistory", []interface{}{arg1, arg2}) + fake.taskListHistoryMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeStorage) TaskListHistoryCallCount() int { + fake.taskListHistoryMutex.RLock() + defer fake.taskListHistoryMutex.RUnlock() + return len(fake.taskListHistoryArgsForCall) +} + +func (fake *FakeStorage) TaskListHistoryCalls(stub func(context.Context, string) (*tasklist.TaskList, error)) { + fake.taskListHistoryMutex.Lock() + defer fake.taskListHistoryMutex.Unlock() + fake.TaskListHistoryStub = stub +} + +func (fake *FakeStorage) TaskListHistoryArgsForCall(i int) (context.Context, string) { + fake.taskListHistoryMutex.RLock() + defer fake.taskListHistoryMutex.RUnlock() + argsForCall := fake.taskListHistoryArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeStorage) TaskListHistoryReturns(result1 *tasklist.TaskList, result2 error) { + fake.taskListHistoryMutex.Lock() + defer fake.taskListHistoryMutex.Unlock() + fake.TaskListHistoryStub = nil + fake.taskListHistoryReturns = struct { + result1 *tasklist.TaskList + result2 error + }{result1, result2} +} + +func (fake *FakeStorage) TaskListHistoryReturnsOnCall(i int, result1 *tasklist.TaskList, result2 error) { + fake.taskListHistoryMutex.Lock() + defer fake.taskListHistoryMutex.Unlock() + fake.TaskListHistoryStub = nil + if fake.taskListHistoryReturnsOnCall == nil { + fake.taskListHistoryReturnsOnCall = make(map[int]struct { + result1 *tasklist.TaskList + result2 error + }) + } + fake.taskListHistoryReturnsOnCall[i] = struct { + result1 *tasklist.TaskList + result2 error + }{result1, result2} +} + func (fake *FakeStorage) TaskListTemplate(arg1 context.Context, arg2 string) (*tasklist.Template, error) { fake.taskListTemplateMutex.Lock() ret, specificReturn := fake.taskListTemplateReturnsOnCall[len(fake.taskListTemplateArgsForCall)] @@ -180,6 +417,12 @@ func (fake *FakeStorage) TaskTemplatesReturnsOnCall(i int, result1 map[string]*t func (fake *FakeStorage) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() + fake.getGroupTasksMutex.RLock() + defer fake.getGroupTasksMutex.RUnlock() + fake.taskListMutex.RLock() + defer fake.taskListMutex.RUnlock() + fake.taskListHistoryMutex.RLock() + defer fake.taskListHistoryMutex.RUnlock() fake.taskListTemplateMutex.RLock() defer fake.taskListTemplateMutex.RUnlock() fake.taskTemplatesMutex.RLock() diff --git a/internal/storage/storage.go b/internal/storage/storage.go index cc16df1cd4392949218e17a91b7ab8995395864d..4a8d1ffaf7089f11273e316f45336238d833579e 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -315,3 +315,45 @@ func (s *Storage) SaveTaskListHistory(ctx context.Context, taskList *tasklist.Ta b := backoff.WithContext(backoff.NewExponentialBackOff(), ctx) return backoff.Retry(insert, b) } + +// TaskList retrieves a tasklist.TaskList from taskLists collection by ID +func (s *Storage) TaskList(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + result := s.taskLists.FindOne(ctx, bson.M{ + "id": taskListID, + }) + + if result.Err() != nil { + if strings.Contains(result.Err().Error(), "no documents in result") { + return nil, errors.New(errors.NotFound, "taskList not found") + } + return nil, result.Err() + } + + var list tasklist.TaskList + if err := result.Decode(&list); err != nil { + return nil, err + } + + return &list, nil +} + +// TaskListHistory retrieves a tasklist.TaskList from taskListHistory collection by ID +func (s *Storage) TaskListHistory(ctx context.Context, taskListID string) (*tasklist.TaskList, error) { + result := s.taskListHistory.FindOne(ctx, bson.M{ + "id": taskListID, + }) + + if result.Err() != nil { + if strings.Contains(result.Err().Error(), "no documents in result") { + return nil, errors.New(errors.NotFound, "taskList not found") + } + return nil, result.Err() + } + + var list tasklist.TaskList + if err := result.Decode(&list); err != nil { + return nil, err + } + + return &list, nil +}