1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package main
import (
"context"
"errors"
"fmt"
"time"
)
type Input struct{}
type A_Output struct{}
type B_Output struct{}
type C_Output struct{}
func ServiceA(i Input) (A_Output, error) {
// simulate a real service call
println("ServiceA is running")
<-time.After(30 * time.Millisecond)
println("ServiceA is done")
return A_Output{}, nil
}
func ServiceB(i Input) (B_Output, error) {
// simulate a real service call
println("ServiceB is running")
<-time.After(1 * time.Millisecond)
println("ServiceB is done")
return B_Output{}, nil
}
func ServiceC(a A_Output, b B_Output) (C_Output, error) {
// simulate a real service call
println("ServiceC is running")
<-time.After(10 * time.Millisecond)
println("ServiceC is done")
return C_Output{}, errors.New("ERROR C")
}
func CallServices(i Input, timeout time.Duration) (C_Output, error) {
ctx, cancel := context.WithTimeout(
context.Background(),
timeout,
)
defer cancel()
a_out := make(chan A_Output, 1)
e_out := make(chan error, 2)
go func() {
defer close(a_out)
a, ok := ServiceA(i)
if ok != nil {
e_out <- ok
println("Got an error from serviceA")
return
}
a_out <- a
}()
b_out := make(chan B_Output, 1)
go func() {
defer close(b_out)
b, ok := ServiceB(i)
if ok != nil {
e_out <- ok
println("Got an error from serviceB")
return
}
b_out <- b
}()
var a A_Output
var b B_Output
for _ = range 2 {
select {
case a = <-a_out:
println("Received value from a_out channel")
a_out = nil
case b = <-b_out:
println("Received value from b_out channel")
b_out = nil
case <-e_out:
println("Received error from e_out (ServiceA or ServiceB)")
return C_Output{}, errors.New("ERROR")
case <-ctx.Done():
println("Received Timeout (ServiceA or ServiceB)")
return C_Output{}, errors.New("TIMEOUT")
}
}
c_out := make(chan C_Output, 1)
go func() {
defer close(c_out)
c, ok := ServiceC(a, b)
if ok != nil {
e_out <- ok
println("Got an error from serviceC")
return
}
c_out <- c
}()
var c C_Output
select {
case c = <-c_out:
println("Received value from c_out channel")
case <-e_out:
println("Received error from e_out channel (ServiceC)")
return C_Output{}, errors.New("ERROR from C")
case <-ctx.Done():
println("Received Timeout from context (ServiceC)")
return C_Output{}, errors.New("Timeout ServiceC")
}
return c, nil
}
func main() {
i := Input{}
c, ok := CallServices(i, 50*time.Millisecond)
if ok != nil {
println("There was an error:", ok.Error())
return
}
fmt.Printf("All Done! %v", c)
}
|