Skip to content
Snippets Groups Projects
Commit b2bcbd05 authored by Lyuben Penkovski's avatar Lyuben Penkovski
Browse files

Merge branch '12-retrieve-task-result' into 'main'

HTTP endpoint to retreive task results

Closes #12

See merge request !7
parents 19ac326f 8bc0a3ec
No related branches found
No related tags found
1 merge request!7HTTP endpoint to retreive task results
Pipeline #50892 passed
Showing
with 345 additions and 25 deletions
...@@ -90,7 +90,7 @@ func main() { ...@@ -90,7 +90,7 @@ func main() {
healthSvc goahealth.Service healthSvc goahealth.Service
) )
{ {
taskSvc = task.New(storage, storage, logger) taskSvc = task.New(storage, storage, cache, logger)
healthSvc = health.New() healthSvc = health.New()
} }
......
...@@ -37,6 +37,16 @@ var _ = Service("task", func() { ...@@ -37,6 +37,16 @@ var _ = Service("task", func() {
Response(StatusOK) Response(StatusOK)
}) })
}) })
Method("TaskResult", func() {
Description("TaskResult retrieves task result from the Cache service.")
Payload(TaskResultRequest)
Result(Any)
HTTP(func() {
GET("/v1/taskResult/{taskID}")
Response(StatusOK)
})
})
}) })
var _ = Service("health", func() { var _ = Service("health", func() {
......
...@@ -15,3 +15,8 @@ var CreateResult = Type("CreateResult", func() { ...@@ -15,3 +15,8 @@ var CreateResult = Type("CreateResult", func() {
Field(1, "taskID", String, "Unique task identifier.") Field(1, "taskID", String, "Unique task identifier.")
Required("taskID") Required("taskID")
}) })
var TaskResultRequest = Type("TaskResultRequest", func() {
Field(1, "taskID", String, "Unique task identifier.")
Required("taskID")
})
...@@ -25,14 +25,14 @@ import ( ...@@ -25,14 +25,14 @@ import (
// //
func UsageCommands() string { func UsageCommands() string {
return `health (liveness|readiness) return `health (liveness|readiness)
task create task (create|task-result)
` `
} }
// UsageExamples produces an example of a valid invocation of the CLI tool. // UsageExamples produces an example of a valid invocation of the CLI tool.
func UsageExamples() string { func UsageExamples() string {
return os.Args[0] + ` health liveness` + "\n" + return os.Args[0] + ` health liveness` + "\n" +
os.Args[0] + ` task create --body "Nam et." --task-name "Minus reprehenderit non quo nihil adipisci." --cache-namespace "Pariatur sequi et." --cache-scope "Corrupti facere sequi tempora eius assumenda molestiae."` + "\n" + os.Args[0] + ` task create --body "Eaque excepturi suscipit veritatis nemo." --task-name "Corrupti facere sequi tempora eius assumenda molestiae." --cache-namespace "Laborum sapiente." --cache-scope "Nam et."` + "\n" +
"" ""
} }
...@@ -59,6 +59,9 @@ func ParseEndpoint( ...@@ -59,6 +59,9 @@ func ParseEndpoint(
taskCreateTaskNameFlag = taskCreateFlags.String("task-name", "REQUIRED", "Task name.") taskCreateTaskNameFlag = taskCreateFlags.String("task-name", "REQUIRED", "Task name.")
taskCreateCacheNamespaceFlag = taskCreateFlags.String("cache-namespace", "", "") taskCreateCacheNamespaceFlag = taskCreateFlags.String("cache-namespace", "", "")
taskCreateCacheScopeFlag = taskCreateFlags.String("cache-scope", "", "") taskCreateCacheScopeFlag = taskCreateFlags.String("cache-scope", "", "")
taskTaskResultFlags = flag.NewFlagSet("task-result", flag.ExitOnError)
taskTaskResultTaskIDFlag = taskTaskResultFlags.String("task-id", "REQUIRED", "Unique task identifier.")
) )
healthFlags.Usage = healthUsage healthFlags.Usage = healthUsage
healthLivenessFlags.Usage = healthLivenessUsage healthLivenessFlags.Usage = healthLivenessUsage
...@@ -66,6 +69,7 @@ func ParseEndpoint( ...@@ -66,6 +69,7 @@ func ParseEndpoint(
taskFlags.Usage = taskUsage taskFlags.Usage = taskUsage
taskCreateFlags.Usage = taskCreateUsage taskCreateFlags.Usage = taskCreateUsage
taskTaskResultFlags.Usage = taskTaskResultUsage
if err := flag.CommandLine.Parse(os.Args[1:]); err != nil { if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
return nil, nil, err return nil, nil, err
...@@ -116,6 +120,9 @@ func ParseEndpoint( ...@@ -116,6 +120,9 @@ func ParseEndpoint(
case "create": case "create":
epf = taskCreateFlags epf = taskCreateFlags
case "task-result":
epf = taskTaskResultFlags
} }
} }
...@@ -154,6 +161,9 @@ func ParseEndpoint( ...@@ -154,6 +161,9 @@ func ParseEndpoint(
case "create": case "create":
endpoint = c.Create() endpoint = c.Create()
data, err = taskc.BuildCreatePayload(*taskCreateBodyFlag, *taskCreateTaskNameFlag, *taskCreateCacheNamespaceFlag, *taskCreateCacheScopeFlag) data, err = taskc.BuildCreatePayload(*taskCreateBodyFlag, *taskCreateTaskNameFlag, *taskCreateCacheNamespaceFlag, *taskCreateCacheScopeFlag)
case "task-result":
endpoint = c.TaskResult()
data, err = taskc.BuildTaskResultPayload(*taskTaskResultTaskIDFlag)
} }
} }
} }
...@@ -206,6 +216,7 @@ Usage: ...@@ -206,6 +216,7 @@ Usage:
COMMAND: COMMAND:
create: Create a task and put it in a queue for execution. create: Create a task and put it in a queue for execution.
task-result: TaskResult retrieves task result from the Cache service.
Additional help: Additional help:
%[1]s task COMMAND --help %[1]s task COMMAND --help
...@@ -221,6 +232,17 @@ Create a task and put it in a queue for execution. ...@@ -221,6 +232,17 @@ Create a task and put it in a queue for execution.
-cache-scope STRING: -cache-scope STRING:
Example: Example:
%[1]s task create --body "Nam et." --task-name "Minus reprehenderit non quo nihil adipisci." --cache-namespace "Pariatur sequi et." --cache-scope "Corrupti facere sequi tempora eius assumenda molestiae." %[1]s task create --body "Eaque excepturi suscipit veritatis nemo." --task-name "Corrupti facere sequi tempora eius assumenda molestiae." --cache-namespace "Laborum sapiente." --cache-scope "Nam et."
`, os.Args[0])
}
func taskTaskResultUsage() {
fmt.Fprintf(os.Stderr, `%[1]s [flags] task task-result -task-id STRING
TaskResult retrieves task result from the Cache service.
-task-id STRING: Unique task identifier.
Example:
%[1]s task task-result --task-id "Et ipsa voluptate."
`, os.Args[0]) `, os.Args[0])
} }
{"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"]}}},"definitions":{"TaskCreateResponseBody":{"title":"TaskCreateResponseBody","type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Eaque excepturi suscipit veritatis nemo."}},"example":{"taskID":"Corrupti quia autem dolorum sunt aperiam quaerat."},"required":["taskID"]}}} {"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/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":"Vel odio et doloribus est quod laborum."}},"example":{"taskID":"Harum aut autem aliquam dolorem non soluta."},"required":["taskID"]}}}
\ No newline at end of file \ No newline at end of file
...@@ -74,6 +74,27 @@ paths: ...@@ -74,6 +74,27 @@ paths:
- taskID - taskID
schemes: schemes:
- http - 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: definitions:
TaskCreateResponseBody: TaskCreateResponseBody:
title: TaskCreateResponseBody title: TaskCreateResponseBody
...@@ -82,8 +103,8 @@ definitions: ...@@ -82,8 +103,8 @@ definitions:
taskID: taskID:
type: string type: string
description: Unique task identifier. description: Unique task identifier.
example: Eaque excepturi suscipit veritatis nemo. example: Vel odio et doloribus est quod laborum.
example: example:
taskID: Corrupti quia autem dolorum sunt aperiam quaerat. taskID: Harum aut autem aliquam dolorem non soluta.
required: required:
- taskID - taskID
{"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":"Vel odio et doloribus est quod laborum."},"example":"Harum aut autem aliquam dolorem non soluta."},{"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":"Eveniet et eligendi sint quibusdam quia maxime.","format":"binary"},"example":"Ipsam et est accusantium."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateResult"},"example":{"taskID":"Facere quibusdam voluptate beatae."}}}}}}}},"components":{"schemas":{"CreateResult":{"type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Et ipsa voluptate."}},"example":{"taskID":"Quo qui fuga impedit eos fuga et."},"required":["taskID"]}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"task","description":"Task service provides endpoints to work with tasks."}]} {"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":"Aut qui aut itaque et commodi vel."},"example":"Sapiente et."},{"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":"Excepturi aut consequatur animi rerum.","format":"binary"},"example":"Dolorem illo officiis ipsa impedit harum et."}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateResult"},"example":{"taskID":"Corrupti quia autem dolorum sunt aperiam quaerat."}}}}}}},"/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":"Delectus natus eos."},"example":"Quae ut dolores ab."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Illum quidem sapiente sed velit.","format":"binary"},"example":"Omnis commodi reiciendis eum non."}}}}}}},"components":{"schemas":{"CreateResult":{"type":"object","properties":{"taskID":{"type":"string","description":"Unique task identifier.","example":"Dolores atque error ab."}},"example":{"taskID":"Laboriosam perspiciatis vitae numquam."},"required":["taskID"]}}},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"task","description":"Task service provides endpoints to work with tasks."}]}
\ No newline at end of file \ No newline at end of file
...@@ -40,8 +40,8 @@ paths: ...@@ -40,8 +40,8 @@ paths:
schema: schema:
type: string type: string
description: Task name. description: Task name.
example: Vel odio et doloribus est quod laborum. example: Aut qui aut itaque et commodi vel.
example: Harum aut autem aliquam dolorem non soluta. example: Sapiente et.
- name: x-cache-namespace - name: x-cache-namespace
in: header in: header
description: Cache key namespace description: Cache key namespace
...@@ -68,9 +68,9 @@ paths: ...@@ -68,9 +68,9 @@ paths:
schema: schema:
type: string type: string
description: Data contains JSON payload that will be used for task execution. description: Data contains JSON payload that will be used for task execution.
example: Eveniet et eligendi sint quibusdam quia maxime. example: Excepturi aut consequatur animi rerum.
format: binary format: binary
example: Ipsam et est accusantium. example: Dolorem illo officiis ipsa impedit harum et.
responses: responses:
"200": "200":
description: OK response. description: OK response.
...@@ -79,7 +79,34 @@ paths: ...@@ -79,7 +79,34 @@ paths:
schema: schema:
$ref: '#/components/schemas/CreateResult' $ref: '#/components/schemas/CreateResult'
example: example:
taskID: Facere quibusdam voluptate beatae. taskID: Corrupti quia autem dolorum sunt aperiam quaerat.
/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: Delectus natus eos.
example: Quae ut dolores ab.
responses:
"200":
description: OK response.
content:
application/json:
schema:
type: string
example: Illum quidem sapiente sed velit.
format: binary
example: Omnis commodi reiciendis eum non.
components: components:
schemas: schemas:
CreateResult: CreateResult:
...@@ -88,9 +115,9 @@ components: ...@@ -88,9 +115,9 @@ components:
taskID: taskID:
type: string type: string
description: Unique task identifier. description: Unique task identifier.
example: Et ipsa voluptate. example: Dolores atque error ab.
example: example:
taskID: Quo qui fuga impedit eos fuga et. taskID: Laboriosam perspiciatis vitae numquam.
required: required:
- taskID - taskID
tags: tags:
......
...@@ -22,7 +22,7 @@ func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCr ...@@ -22,7 +22,7 @@ func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCr
{ {
err = json.Unmarshal([]byte(taskCreateBody), &body) err = json.Unmarshal([]byte(taskCreateBody), &body)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Nam et.\"") return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "\"Eaque excepturi suscipit veritatis nemo.\"")
} }
} }
var taskName string var taskName string
...@@ -51,3 +51,16 @@ func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCr ...@@ -51,3 +51,16 @@ func BuildCreatePayload(taskCreateBody string, taskCreateTaskName string, taskCr
return res, nil return res, nil
} }
// BuildTaskResultPayload builds the payload for the task TaskResult endpoint
// from CLI flags.
func BuildTaskResultPayload(taskTaskResultTaskID string) (*task.TaskResultRequest, error) {
var taskID string
{
taskID = taskTaskResultTaskID
}
v := &task.TaskResultRequest{}
v.TaskID = taskID
return v, nil
}
...@@ -20,6 +20,10 @@ type Client struct { ...@@ -20,6 +20,10 @@ type Client struct {
// Create Doer is the HTTP client used to make requests to the Create endpoint. // Create Doer is the HTTP client used to make requests to the Create endpoint.
CreateDoer goahttp.Doer CreateDoer goahttp.Doer
// TaskResult Doer is the HTTP client used to make requests to the TaskResult
// endpoint.
TaskResultDoer goahttp.Doer
// RestoreResponseBody controls whether the response bodies are reset after // RestoreResponseBody controls whether the response bodies are reset after
// decoding so they can be read again. // decoding so they can be read again.
RestoreResponseBody bool RestoreResponseBody bool
...@@ -41,6 +45,7 @@ func NewClient( ...@@ -41,6 +45,7 @@ func NewClient(
) *Client { ) *Client {
return &Client{ return &Client{
CreateDoer: doer, CreateDoer: doer,
TaskResultDoer: doer,
RestoreResponseBody: restoreBody, RestoreResponseBody: restoreBody,
scheme: scheme, scheme: scheme,
host: host, host: host,
...@@ -72,3 +77,22 @@ func (c *Client) Create() goa.Endpoint { ...@@ -72,3 +77,22 @@ func (c *Client) Create() goa.Endpoint {
return decodeResponse(resp) return decodeResponse(resp)
} }
} }
// TaskResult returns an endpoint that makes HTTP requests to the task service
// TaskResult server.
func (c *Client) TaskResult() goa.Endpoint {
var (
decodeResponse = DecodeTaskResultResponse(c.decoder, c.RestoreResponseBody)
)
return func(ctx context.Context, v interface{}) (interface{}, error) {
req, err := c.BuildTaskResultRequest(ctx, v)
if err != nil {
return nil, err
}
resp, err := c.TaskResultDoer.Do(req)
if err != nil {
return nil, goahttp.ErrRequestError("task", "TaskResult", err)
}
return decodeResponse(resp)
}
}
...@@ -106,3 +106,63 @@ func DecodeCreateResponse(decoder func(*http.Response) goahttp.Decoder, restoreB ...@@ -106,3 +106,63 @@ func DecodeCreateResponse(decoder func(*http.Response) goahttp.Decoder, restoreB
} }
} }
} }
// BuildTaskResultRequest instantiates a HTTP request object with method and
// path set to call the "task" service "TaskResult" endpoint
func (c *Client) BuildTaskResultRequest(ctx context.Context, v interface{}) (*http.Request, error) {
var (
taskID string
)
{
p, ok := v.(*task.TaskResultRequest)
if !ok {
return nil, goahttp.ErrInvalidType("task", "TaskResult", "*task.TaskResultRequest", v)
}
taskID = p.TaskID
}
u := &url.URL{Scheme: c.scheme, Host: c.host, Path: TaskResultTaskPath(taskID)}
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, goahttp.ErrInvalidURL("task", "TaskResult", u.String(), err)
}
if ctx != nil {
req = req.WithContext(ctx)
}
return req, nil
}
// DecodeTaskResultResponse returns a decoder for responses returned by the
// task TaskResult endpoint. restoreBody controls whether the response body
// should be restored after having been read.
func DecodeTaskResultResponse(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.StatusOK:
var (
body interface{}
err error
)
err = decoder(resp).Decode(&body)
if err != nil {
return nil, goahttp.ErrDecodingError("task", "TaskResult", err)
}
return body, nil
default:
body, _ := ioutil.ReadAll(resp.Body)
return nil, goahttp.ErrInvalidResponse("task", "TaskResult", resp.StatusCode, string(body))
}
}
}
...@@ -15,3 +15,8 @@ import ( ...@@ -15,3 +15,8 @@ import (
func CreateTaskPath(taskName string) string { func CreateTaskPath(taskName string) string {
return fmt.Sprintf("/v1/task/%v", taskName) return fmt.Sprintf("/v1/task/%v", taskName)
} }
// TaskResultTaskPath returns the URL path to the task service TaskResult HTTP endpoint.
func TaskResultTaskPath(taskID string) string {
return fmt.Sprintf("/v1/taskResult/%v", taskID)
}
...@@ -66,3 +66,31 @@ func DecodeCreateRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp. ...@@ -66,3 +66,31 @@ func DecodeCreateRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.
return payload, nil return payload, nil
} }
} }
// EncodeTaskResultResponse returns an encoder for responses returned by the
// task TaskResult endpoint.
func EncodeTaskResultResponse(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.(interface{})
enc := encoder(ctx, w)
body := res
w.WriteHeader(http.StatusOK)
return enc.Encode(body)
}
}
// DecodeTaskResultRequest returns a decoder for requests sent to the task
// TaskResult endpoint.
func DecodeTaskResultRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (interface{}, error) {
return func(r *http.Request) (interface{}, error) {
var (
taskID string
params = mux.Vars(r)
)
taskID = params["taskID"]
payload := NewTaskResultRequest(taskID)
return payload, nil
}
}
...@@ -15,3 +15,8 @@ import ( ...@@ -15,3 +15,8 @@ import (
func CreateTaskPath(taskName string) string { func CreateTaskPath(taskName string) string {
return fmt.Sprintf("/v1/task/%v", taskName) return fmt.Sprintf("/v1/task/%v", taskName)
} }
// TaskResultTaskPath returns the URL path to the task service TaskResult HTTP endpoint.
func TaskResultTaskPath(taskID string) string {
return fmt.Sprintf("/v1/taskResult/%v", taskID)
}
...@@ -18,8 +18,9 @@ import ( ...@@ -18,8 +18,9 @@ import (
// Server lists the task service endpoint HTTP handlers. // Server lists the task service endpoint HTTP handlers.
type Server struct { type Server struct {
Mounts []*MountPoint Mounts []*MountPoint
Create http.Handler Create http.Handler
TaskResult http.Handler
} }
// ErrorNamer is an interface implemented by generated error structs that // ErrorNamer is an interface implemented by generated error structs that
...@@ -56,8 +57,10 @@ func New( ...@@ -56,8 +57,10 @@ func New(
return &Server{ return &Server{
Mounts: []*MountPoint{ Mounts: []*MountPoint{
{"Create", "POST", "/v1/task/{taskName}"}, {"Create", "POST", "/v1/task/{taskName}"},
{"TaskResult", "GET", "/v1/taskResult/{taskID}"},
}, },
Create: NewCreateHandler(e.Create, mux, decoder, encoder, errhandler, formatter), Create: NewCreateHandler(e.Create, mux, decoder, encoder, errhandler, formatter),
TaskResult: NewTaskResultHandler(e.TaskResult, mux, decoder, encoder, errhandler, formatter),
} }
} }
...@@ -67,11 +70,13 @@ func (s *Server) Service() string { return "task" } ...@@ -67,11 +70,13 @@ func (s *Server) Service() string { return "task" }
// Use wraps the server handlers with the given middleware. // Use wraps the server handlers with the given middleware.
func (s *Server) Use(m func(http.Handler) http.Handler) { func (s *Server) Use(m func(http.Handler) http.Handler) {
s.Create = m(s.Create) s.Create = m(s.Create)
s.TaskResult = m(s.TaskResult)
} }
// Mount configures the mux to serve the task endpoints. // Mount configures the mux to serve the task endpoints.
func Mount(mux goahttp.Muxer, h *Server) { func Mount(mux goahttp.Muxer, h *Server) {
MountCreateHandler(mux, h.Create) MountCreateHandler(mux, h.Create)
MountTaskResultHandler(mux, h.TaskResult)
} }
// Mount configures the mux to serve the task endpoints. // Mount configures the mux to serve the task endpoints.
...@@ -129,3 +134,54 @@ func NewCreateHandler( ...@@ -129,3 +134,54 @@ func NewCreateHandler(
} }
}) })
} }
// MountTaskResultHandler configures the mux to serve the "task" service
// "TaskResult" endpoint.
func MountTaskResultHandler(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/taskResult/{taskID}", f)
}
// NewTaskResultHandler creates a HTTP handler which loads the HTTP request and
// calls the "task" service "TaskResult" endpoint.
func NewTaskResultHandler(
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 = DecodeTaskResultRequest(mux, decoder)
encodeResponse = EncodeTaskResultResponse(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, "TaskResult")
ctx = context.WithValue(ctx, goa.ServiceKey, "task")
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)
}
})
}
...@@ -39,3 +39,11 @@ func NewCreateRequest(body interface{}, taskName string, cacheNamespace *string, ...@@ -39,3 +39,11 @@ func NewCreateRequest(body interface{}, taskName string, cacheNamespace *string,
return res return res
} }
// NewTaskResultRequest builds a task service TaskResult endpoint payload.
func NewTaskResultRequest(taskID string) *task.TaskResultRequest {
v := &task.TaskResultRequest{}
v.TaskID = taskID
return v
}
...@@ -15,13 +15,15 @@ import ( ...@@ -15,13 +15,15 @@ import (
// Client is the "task" service client. // Client is the "task" service client.
type Client struct { type Client struct {
CreateEndpoint goa.Endpoint CreateEndpoint goa.Endpoint
TaskResultEndpoint goa.Endpoint
} }
// NewClient initializes a "task" service client given the endpoints. // NewClient initializes a "task" service client given the endpoints.
func NewClient(create goa.Endpoint) *Client { func NewClient(create, taskResult goa.Endpoint) *Client {
return &Client{ return &Client{
CreateEndpoint: create, CreateEndpoint: create,
TaskResultEndpoint: taskResult,
} }
} }
...@@ -34,3 +36,13 @@ func (c *Client) Create(ctx context.Context, p *CreateRequest) (res *CreateResul ...@@ -34,3 +36,13 @@ func (c *Client) Create(ctx context.Context, p *CreateRequest) (res *CreateResul
} }
return ires.(*CreateResult), nil return ires.(*CreateResult), nil
} }
// TaskResult calls the "TaskResult" endpoint of the "task" service.
func (c *Client) TaskResult(ctx context.Context, p *TaskResultRequest) (res interface{}, err error) {
var ires interface{}
ires, err = c.TaskResultEndpoint(ctx, p)
if err != nil {
return
}
return ires.(interface{}), nil
}
...@@ -15,19 +15,22 @@ import ( ...@@ -15,19 +15,22 @@ import (
// Endpoints wraps the "task" service endpoints. // Endpoints wraps the "task" service endpoints.
type Endpoints struct { type Endpoints struct {
Create goa.Endpoint Create goa.Endpoint
TaskResult goa.Endpoint
} }
// NewEndpoints wraps the methods of the "task" service with endpoints. // NewEndpoints wraps the methods of the "task" service with endpoints.
func NewEndpoints(s Service) *Endpoints { func NewEndpoints(s Service) *Endpoints {
return &Endpoints{ return &Endpoints{
Create: NewCreateEndpoint(s), Create: NewCreateEndpoint(s),
TaskResult: NewTaskResultEndpoint(s),
} }
} }
// Use applies the given middleware to all the "task" service endpoints. // Use applies the given middleware to all the "task" service endpoints.
func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) {
e.Create = m(e.Create) e.Create = m(e.Create)
e.TaskResult = m(e.TaskResult)
} }
// NewCreateEndpoint returns an endpoint function that calls the method // NewCreateEndpoint returns an endpoint function that calls the method
...@@ -38,3 +41,12 @@ func NewCreateEndpoint(s Service) goa.Endpoint { ...@@ -38,3 +41,12 @@ func NewCreateEndpoint(s Service) goa.Endpoint {
return s.Create(ctx, p) return s.Create(ctx, p)
} }
} }
// NewTaskResultEndpoint returns an endpoint function that calls the method
// "TaskResult" of service "task".
func NewTaskResultEndpoint(s Service) goa.Endpoint {
return func(ctx context.Context, req interface{}) (interface{}, error) {
p := req.(*TaskResultRequest)
return s.TaskResult(ctx, p)
}
}
...@@ -15,6 +15,8 @@ import ( ...@@ -15,6 +15,8 @@ import (
type Service interface { type Service interface {
// Create a task and put it in a queue for execution. // Create a task and put it in a queue for execution.
Create(context.Context, *CreateRequest) (res *CreateResult, err error) Create(context.Context, *CreateRequest) (res *CreateResult, err error)
// TaskResult retrieves task result from the Cache service.
TaskResult(context.Context, *TaskResultRequest) (res interface{}, err error)
} }
// ServiceName is the name of the service as defined in the design. This is the // ServiceName is the name of the service as defined in the design. This is the
...@@ -25,7 +27,7 @@ const ServiceName = "task" ...@@ -25,7 +27,7 @@ const ServiceName = "task"
// MethodNames lists the service method names as defined in the design. These // 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 // are the same values that are set in the endpoint request contexts under the
// MethodKey key. // MethodKey key.
var MethodNames = [1]string{"Create"} var MethodNames = [2]string{"Create", "TaskResult"}
// CreateRequest is the payload type of the task service Create method. // CreateRequest is the payload type of the task service Create method.
type CreateRequest struct { type CreateRequest struct {
...@@ -44,3 +46,9 @@ type CreateResult struct { ...@@ -44,3 +46,9 @@ type CreateResult struct {
// Unique task identifier. // Unique task identifier.
TaskID string TaskID string
} }
// TaskResultRequest is the payload type of the task service TaskResult method.
type TaskResultRequest struct {
// Unique task identifier.
TaskID string
}
...@@ -7,6 +7,7 @@ require ( ...@@ -7,6 +7,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 github.com/cenkalti/backoff/v4 v4.1.3
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/kelseyhightower/envconfig v1.4.0 github.com/kelseyhightower/envconfig v1.4.0
github.com/stretchr/testify v1.7.0
go.mongodb.org/mongo-driver v1.8.4 go.mongodb.org/mongo-driver v1.8.4
go.uber.org/zap v1.21.0 go.uber.org/zap v1.21.0
goa.design/goa/v3 v3.7.0 goa.design/goa/v3 v3.7.0
...@@ -14,6 +15,7 @@ require ( ...@@ -14,6 +15,7 @@ require (
) )
require ( require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 // indirect github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 // indirect
github.com/dimfeld/httptreemux/v5 v5.4.0 // indirect github.com/dimfeld/httptreemux/v5 v5.4.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect github.com/go-stack/stack v1.8.0 // indirect
...@@ -25,6 +27,7 @@ require ( ...@@ -25,6 +27,7 @@ require (
github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/compress v1.13.6 // indirect
github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d // indirect github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect
github.com/smartystreets/assertions v1.2.1 // indirect github.com/smartystreets/assertions v1.2.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
...@@ -41,4 +44,5 @@ require ( ...@@ -41,4 +44,5 @@ require (
golang.org/x/tools v0.1.10 // indirect golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
) )
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment