Skip to content

Commit 73c27d5

Browse files
authored
Merge pull request #8 from Azure/haitao/fix_err_case
Haitao/fix_err_case
2 parents b1b1221 + 9b1bede commit 73c27d5

9 files changed

+116
-59
lines changed

go.mod

+8
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,11 @@ module github.com/Azure/go-asyncjob
33
go 1.18
44

55
require github.com/Azure/go-asynctask v1.3.0
6+
7+
require (
8+
github.com/davecgh/go-spew v1.1.1 // indirect
9+
github.com/pmezard/go-difflib v1.0.0 // indirect
10+
github.com/stretchr/objx v0.5.0 // indirect
11+
github.com/stretchr/testify v1.8.1 // indirect
12+
gopkg.in/yaml.v3 v3.0.1 // indirect
13+
)

go.sum

+13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
github.com/Azure/go-asynctask v1.3.0 h1:QBx9mGbGi4Urz4YeZ3o1c7cLGL4iUch+mGgNGupTLMI=
22
github.com/Azure/go-asynctask v1.3.0/go.mod h1:S1Ee5SVnt6ZUJ84brodPiHvoNfN2wgDyVO7UYTI5WeM=
3+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
34
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
46
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
7+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
8+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
9+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
10+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
11+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
12+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
13+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
514
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
15+
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
16+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
17+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
618
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
19+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

graph/error.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
package graph
22

3-
type GraphErrorCode string
3+
type GraphCodeError string
44

55
const (
6-
ErrDuplicateNode GraphErrorCode = "node with same key already exists in this graph"
7-
ErrConnectNotExistingNode GraphErrorCode = "node to connect does not exist in this graph"
6+
ErrDuplicateNode GraphCodeError = "node with same key already exists in this graph"
7+
ErrConnectNotExistingNode GraphCodeError = "node to connect does not exist in this graph"
88
)
99

10-
func (ge GraphErrorCode) Error() string {
10+
func (ge GraphCodeError) Error() string {
1111
return string(ge)
1212
}
1313

1414
type GraphError struct {
15-
Code GraphErrorCode
15+
Code GraphCodeError
1616
Message string
1717
}
1818

19+
func NewGraphError(code GraphCodeError, message string) *GraphError {
20+
return &GraphError{
21+
Code: code,
22+
Message: message,
23+
}
24+
}
25+
1926
func (ge *GraphError) Error() string {
2027
return ge.Code.Error() + ": " + ge.Message
2128
}

graph/graph.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package graph
22

33
import (
44
"bytes"
5+
"fmt"
56
)
67

78
// NodeConstrain is a constraint for a node in a graph
@@ -56,25 +57,26 @@ func NewGraph[NT NodeConstrain](edgeSpecFunc EdgeSpecFunc[NT]) *Graph[NT] {
5657
func (g *Graph[NT]) AddNode(n NT) error {
5758
nodeKey := n.DotSpec().ID
5859
if _, ok := g.nodes[nodeKey]; ok {
59-
return ErrDuplicateNode
60+
return NewGraphError(ErrDuplicateNode, fmt.Sprintf("node with key %s already exists in this graph", nodeKey))
6061
}
6162
g.nodes[nodeKey] = n
6263

6364
return nil
6465
}
6566

66-
func (g *Graph[NT]) Connect(from, to string) error {
67-
var nodeFrom, nodeTo NT
67+
func (g *Graph[NT]) Connect(from, to NT) error {
68+
fromNodeKey := from.DotSpec().ID
69+
toNodeKey := to.DotSpec().ID
6870
var ok bool
69-
if nodeFrom, ok = g.nodes[from]; !ok {
70-
return ErrConnectNotExistingNode
71+
if from, ok = g.nodes[fromNodeKey]; !ok {
72+
return NewGraphError(ErrConnectNotExistingNode, fmt.Sprintf("cannot connect node %s, it's not added in this graph yet", fromNodeKey))
7173
}
7274

73-
if nodeTo, ok = g.nodes[to]; !ok {
74-
return ErrConnectNotExistingNode
75+
if to, ok = g.nodes[toNodeKey]; !ok {
76+
return NewGraphError(ErrConnectNotExistingNode, fmt.Sprintf("cannot connect node %s, it's not added in this graph yet", toNodeKey))
7577
}
7678

77-
g.nodeEdges[from] = append(g.nodeEdges[from], &Edge[NT]{From: nodeFrom, To: nodeTo})
79+
g.nodeEdges[fromNodeKey] = append(g.nodeEdges[fromNodeKey], &Edge[NT]{From: from, To: to})
7880
return nil
7981
}
8082

graph/graph_test.go

+20-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
package graph_test
22

33
import (
4+
"errors"
45
"fmt"
56
"testing"
67

78
"github.com/Azure/go-asyncjob/graph"
9+
"github.com/stretchr/testify/assert"
810
)
911

10-
func TestSimpleJob(t *testing.T) {
11-
g := graph.NewGraph[*testNode](edgeSpecFromConnection)
12+
func TestSimpleGraph(t *testing.T) {
13+
g := graph.NewGraph(edgeSpecFromConnection)
1214
root := &testNode{Name: "root"}
1315
g.AddNode(root)
1416
calc1 := &testNode{Name: "calc1"}
@@ -18,16 +20,25 @@ func TestSimpleJob(t *testing.T) {
1820
summary := &testNode{Name: "summary"}
1921
g.AddNode(summary)
2022

21-
g.Connect(root.DotSpec().ID, calc1.DotSpec().ID)
22-
g.Connect(root.DotSpec().ID, calc2.DotSpec().ID)
23-
g.Connect(calc1.DotSpec().ID, summary.DotSpec().ID)
24-
g.Connect(calc2.DotSpec().ID, summary.DotSpec().ID)
23+
g.Connect(root, calc1)
24+
g.Connect(root, calc2)
25+
g.Connect(calc1, summary)
26+
g.Connect(calc2, summary)
2527

26-
graph, err := g.ToDotGraph()
28+
graphStr, err := g.ToDotGraph()
2729
if err != nil {
28-
t.Fatal(err)
30+
assert.NoError(t, err)
2931
}
30-
fmt.Println(graph)
32+
t.Log(graphStr)
33+
34+
err = g.AddNode(calc1)
35+
assert.Error(t, err)
36+
assert.True(t, errors.Is(err, graph.ErrDuplicateNode))
37+
38+
calc3 := &testNode{Name: "calc3"}
39+
err = g.Connect(root, calc3)
40+
assert.Error(t, err)
41+
assert.True(t, errors.Is(err, graph.ErrConnectNotExistingNode))
3142
}
3243

3344
type testNode struct {

job.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func (j *Job) AddStep(step StepMeta, precedingSteps ...StepMeta) {
9191
stepNode := newStepNode(step)
9292
j.stepsDag.AddNode(stepNode)
9393
for _, precedingStep := range precedingSteps {
94-
j.stepsDag.Connect(precedingStep.getID(), step.getID())
94+
j.stepsDag.Connect(newStepNode(precedingStep), stepNode)
9595
}
9696
}
9797

job_test.go

+21-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
package asyncjob
1+
package asyncjob_test
22

33
import (
44
"context"
55
"fmt"
66
"testing"
77
"time"
8+
9+
"github.com/Azure/go-asyncjob"
10+
"github.com/stretchr/testify/assert"
811
)
912

1013
func TestSimpleJob(t *testing.T) {
@@ -14,15 +17,18 @@ func TestSimpleJob(t *testing.T) {
1417
Query1: "query1",
1518
Table2: "table2",
1619
Query2: "query2",
17-
RetryPolicies: map[string]RetryPolicy{},
20+
RetryPolicies: map[string]asyncjob.RetryPolicy{},
1821
}
1922
jb := sb.BuildJob(context.Background())
2023

2124
jb.Start(context.Background())
22-
jb.Wait(context.Background())
25+
jobErr := jb.Wait(context.Background())
26+
if jobErr != nil {
27+
assert.NoError(t, jobErr)
28+
}
2329

24-
dotGraph, err := jb.Visualize()
25-
if err != nil {
30+
dotGraph, vizErr := jb.Visualize()
31+
if vizErr != nil {
2632
t.FailNow()
2733
}
2834
fmt.Println(dotGraph)
@@ -36,12 +42,16 @@ func TestSimpleJobError(t *testing.T) {
3642
Table2: "table2",
3743
Query2: "query2",
3844
ErrorInjection: map[string]func() error{"ExecuteQuery.query2": getErrorFunc(fmt.Errorf("table2 schema error"), 1)},
39-
RetryPolicies: map[string]RetryPolicy{},
45+
RetryPolicies: map[string]asyncjob.RetryPolicy{},
4046
}
4147
jb := sb.BuildJob(context.Background())
4248

4349
jb.Start(context.Background())
4450
jb.Wait(context.Background())
51+
jobErr := jb.Wait(context.Background())
52+
if jobErr != nil {
53+
assert.Error(t, jobErr)
54+
}
4555

4656
dotGraph, err := jb.Visualize()
4757
if err != nil {
@@ -63,7 +73,7 @@ func TestSimpleJobPanic(t *testing.T) {
6373
"GetConnection": getErrorFunc(fmt.Errorf("InternalServerError"), 1),
6474
"ExecuteQuery.panicQuery1": getPanicFunc(4),
6575
},
66-
RetryPolicies: map[string]RetryPolicy{
76+
RetryPolicies: map[string]asyncjob.RetryPolicy{
6777
"CheckAuth": linearRetry, // coverage for AddStep
6878
"GetConnection": linearRetry, // coverage for StepAfter
6979
"QueryTable1": linearRetry, // coverage for StepAfterBoth
@@ -72,8 +82,10 @@ func TestSimpleJobPanic(t *testing.T) {
7282
jb := sb.BuildJob(context.Background())
7383

7484
jb.Start(context.Background())
75-
err := jb.Wait(context.Background())
76-
fmt.Print(err)
85+
jobErr := jb.Wait(context.Background())
86+
if jobErr != nil {
87+
assert.Error(t, jobErr)
88+
}
7789

7890
dotGraph, err := jb.Visualize()
7991
if err != nil {

job_builder.go step_builder.go

+12-9
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,15 @@ func AddStep[T any](bCtx context.Context, j JobInterface, stepName string, stepF
7373
result, err = stepFunc(j.RuntimeContext())
7474
}
7575

76+
step.executionData.Duration = time.Since(step.executionData.StartTime)
77+
7678
if err != nil {
7779
step.state = StepStateFailed
80+
return nil, newStepError(stepName, err)
7881
} else {
7982
step.state = StepStateCompleted
83+
return result, nil
8084
}
81-
82-
step.executionData.Duration = time.Since(step.executionData.StartTime)
83-
return result, newStepError(stepName, err)
8485
}
8586

8687
step.task = asynctask.Start(bCtx, instrumentedFunc)
@@ -136,14 +137,15 @@ func StepAfter[T, S any](bCtx context.Context, j JobInterface, stepName string,
136137
result, err = stepFunc(j.RuntimeContext(), t)
137138
}
138139

140+
step.executionData.Duration = time.Since(step.executionData.StartTime)
141+
139142
if err != nil {
140143
step.state = StepStateFailed
144+
return nil, newStepError(stepName, err)
141145
} else {
142146
step.state = StepStateCompleted
147+
return result, nil
143148
}
144-
145-
step.executionData.Duration = time.Since(step.executionData.StartTime)
146-
return result, newStepError(stepName, err)
147149
}
148150

149151
step.task = asynctask.ContinueWith(bCtx, parentStep.task, instrumentedFunc)
@@ -203,14 +205,15 @@ func StepAfterBoth[T, S, R any](bCtx context.Context, j JobInterface, stepName s
203205
result, err = stepFunc(j.RuntimeContext(), t, s)
204206
}
205207

208+
step.executionData.Duration = time.Since(step.executionData.StartTime)
209+
206210
if err != nil {
207211
step.state = StepStateFailed
212+
return nil, newStepError(stepName, err)
208213
} else {
209214
step.state = StepStateCompleted
215+
return result, nil
210216
}
211-
212-
step.executionData.Duration = time.Since(step.executionData.StartTime)
213-
return result, newStepError(stepName, err)
214217
}
215218

216219
step.task = asynctask.AfterBoth(bCtx, parentStepT.task, parentStepS.task, instrumentedFunc)

util_test.go

+19-18
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
package asyncjob
1+
package asyncjob_test
22

33
import (
44
"context"
55
"fmt"
66
"time"
77

8+
"github.com/Azure/go-asyncjob"
89
"github.com/Azure/go-asynctask"
910
)
1011

@@ -15,7 +16,7 @@ type SqlSummaryJobLib struct {
1516
Table2 string
1617
Query2 string
1718
ErrorInjection map[string]func() error
18-
RetryPolicies map[string]RetryPolicy
19+
RetryPolicies map[string]asyncjob.RetryPolicy
1920
}
2021

2122
type SqlConnection struct {
@@ -102,26 +103,26 @@ func (sql *SqlSummaryJobLib) EmailNotification(ctx context.Context) error {
102103
return nil
103104
}
104105

105-
func (sql *SqlSummaryJobLib) BuildJob(bCtx context.Context) *Job {
106-
job := NewJob("sqlSummaryJob")
106+
func (sql *SqlSummaryJobLib) BuildJob(bCtx context.Context) *asyncjob.Job {
107+
job := asyncjob.NewJob("sqlSummaryJob")
107108

108-
serverNameParamTask := InputParam(bCtx, job, "serverName", &sql.ServerName)
109-
connTsk, _ := StepAfter(bCtx, job, "GetConnection", serverNameParamTask, sql.GetConnection, WithRetry(sql.RetryPolicies["GetConnection"]))
109+
serverNameParamTask := asyncjob.InputParam(bCtx, job, "serverName", &sql.ServerName)
110+
connTsk, _ := asyncjob.StepAfter(bCtx, job, "GetConnection", serverNameParamTask, sql.GetConnection, asyncjob.WithRetry(sql.RetryPolicies["GetConnection"]))
110111

111-
checkAuthTask, _ := AddStep(bCtx, job, "CheckAuth", asynctask.ActionToFunc(sql.CheckAuth), WithRetry(sql.RetryPolicies["CheckAuth"]))
112+
checkAuthTask, _ := asyncjob.AddStep(bCtx, job, "CheckAuth", asynctask.ActionToFunc(sql.CheckAuth), asyncjob.WithRetry(sql.RetryPolicies["CheckAuth"]))
112113

113-
table1ParamTsk := InputParam(bCtx, job, "table1", &sql.Table1)
114-
table1ClientTsk, _ := StepAfterBoth(bCtx, job, "getTableClient1", connTsk, table1ParamTsk, sql.GetTableClient)
115-
query1ParamTsk := InputParam(bCtx, job, "query1", &sql.Query1)
116-
qery1ResultTsk, _ := StepAfterBoth(bCtx, job, "QueryTable1", table1ClientTsk, query1ParamTsk, sql.ExecuteQuery, WithRetry(sql.RetryPolicies["QueryTable1"]), ExecuteAfter(checkAuthTask))
114+
table1ParamTsk := asyncjob.InputParam(bCtx, job, "table1", &sql.Table1)
115+
table1ClientTsk, _ := asyncjob.StepAfterBoth(bCtx, job, "getTableClient1", connTsk, table1ParamTsk, sql.GetTableClient)
116+
query1ParamTsk := asyncjob.InputParam(bCtx, job, "query1", &sql.Query1)
117+
qery1ResultTsk, _ := asyncjob.StepAfterBoth(bCtx, job, "QueryTable1", table1ClientTsk, query1ParamTsk, sql.ExecuteQuery, asyncjob.WithRetry(sql.RetryPolicies["QueryTable1"]), asyncjob.ExecuteAfter(checkAuthTask))
117118

118-
table2ParamTsk := InputParam(bCtx, job, "table2", &sql.Table2)
119-
table2ClientTsk, _ := StepAfterBoth(bCtx, job, "getTableClient2", connTsk, table2ParamTsk, sql.GetTableClient)
120-
query2ParamTsk := InputParam(bCtx, job, "query2", &sql.Query2)
121-
qery2ResultTsk, _ := StepAfterBoth(bCtx, job, "QueryTable2", table2ClientTsk, query2ParamTsk, sql.ExecuteQuery, WithRetry(sql.RetryPolicies["QueryTable2"]), ExecuteAfter(checkAuthTask))
119+
table2ParamTsk := asyncjob.InputParam(bCtx, job, "table2", &sql.Table2)
120+
table2ClientTsk, _ := asyncjob.StepAfterBoth(bCtx, job, "getTableClient2", connTsk, table2ParamTsk, sql.GetTableClient)
121+
query2ParamTsk := asyncjob.InputParam(bCtx, job, "query2", &sql.Query2)
122+
qery2ResultTsk, _ := asyncjob.StepAfterBoth(bCtx, job, "QueryTable2", table2ClientTsk, query2ParamTsk, sql.ExecuteQuery, asyncjob.WithRetry(sql.RetryPolicies["QueryTable2"]), asyncjob.ExecuteAfter(checkAuthTask))
122123

123-
summaryTsk, _ := StepAfterBoth(bCtx, job, "summarize", qery1ResultTsk, qery2ResultTsk, sql.SummarizeQueryResult)
124-
AddStep(bCtx, job, "emailNotification", asynctask.ActionToFunc(sql.EmailNotification), ExecuteAfter(summaryTsk))
124+
summaryTsk, _ := asyncjob.StepAfterBoth(bCtx, job, "summarize", qery1ResultTsk, qery2ResultTsk, sql.SummarizeQueryResult)
125+
asyncjob.AddStep(bCtx, job, "emailNotification", asynctask.ActionToFunc(sql.EmailNotification), asyncjob.ExecuteAfter(summaryTsk))
125126
return job
126127
}
127128

@@ -131,7 +132,7 @@ type linearRetryPolicy struct {
131132
tried int
132133
}
133134

134-
func newLinearRetryPolicy(sleepInterval time.Duration, maxRetryCount int) RetryPolicy {
135+
func newLinearRetryPolicy(sleepInterval time.Duration, maxRetryCount int) asyncjob.RetryPolicy {
135136
return &linearRetryPolicy{
136137
sleepInterval: sleepInterval,
137138
maxRetryCount: maxRetryCount,

0 commit comments

Comments
 (0)