forked from go-chassis/go-chassis
/
fault_inject_handler.go
executable file
·98 lines (82 loc) · 2.88 KB
/
fault_inject_handler.go
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
package handler
import (
"errors"
"net/http"
"strings"
"github.com/go-chassis/go-chassis/client/rest"
"github.com/go-chassis/go-chassis/core/config"
"github.com/go-chassis/go-chassis/core/config/model"
"github.com/go-chassis/go-chassis/core/fault"
"github.com/go-chassis/go-chassis/core/invocation"
"github.com/go-chassis/go-chassis/core/lager"
"github.com/valyala/fasthttp"
)
// constant for fault handler name
const (
FaultHandlerName = "fault-inject"
)
// FaultHandler handler
type FaultHandler struct{}
// newFaultHandler fault handle gives the object of FaultHandler
func newFaultHandler() Handler {
return &FaultHandler{}
}
// Name function returns fault-inject string
func (rl *FaultHandler) Name() string {
return "fault-inject"
}
// Handle is to handle the API
func (rl *FaultHandler) Handle(chain *Chain, inv *invocation.Invocation, cb invocation.ResponseCallBack) {
faultStruct := GetFaultConfig(inv.Protocol, inv.MicroServiceName, inv.SchemaID, inv.OperationID)
faultConfig := model.FaultProtocolStruct{}
faultConfig.Fault = make(map[string]model.Fault)
faultConfig.Fault[inv.Protocol] = faultStruct
faultInject, ok := fault.Injectors[inv.Protocol]
r := &invocation.Response{}
if !ok {
lager.Logger.Warnf("fault injection doesn't support for protocol ", errors.New(inv.Protocol))
r.Err = nil
cb(r)
return
}
faultValue := faultConfig.Fault[inv.Protocol]
err := faultInject(faultValue, inv)
if err != nil {
if strings.Contains(err.Error(), "injecting abort") {
switch inv.Reply.(type) {
case *rest.Response:
resp := inv.Reply.(*rest.Response)
resp.SetStatusCode(faultConfig.Fault[inv.Protocol].Abort.HTTPStatus)
case *fasthttp.Response:
resp := inv.Reply.(*fasthttp.Response)
resp.SetStatusCode(faultConfig.Fault[inv.Protocol].Abort.HTTPStatus)
}
r.Status = faultConfig.Fault[inv.Protocol].Abort.HTTPStatus
} else {
switch inv.Reply.(type) {
case *rest.Response:
resp := inv.Reply.(*rest.Response)
resp.SetStatusCode(http.StatusBadRequest)
case *fasthttp.Response:
resp := inv.Reply.(*fasthttp.Response)
resp.SetStatusCode(http.StatusBadRequest)
}
r.Status = http.StatusBadRequest
}
r.Err = fault.FaultError{Message: err.Error()}
cb(r)
return
}
chain.Next(inv, func(r *invocation.Response) error {
return cb(r)
})
}
// GetFaultConfig get faultconfig
func GetFaultConfig(protocol, microServiceName, schemaID, operationID string) model.Fault {
faultStruct := model.Fault{}
faultStruct.Abort.Percent = config.GetAbortPercent(protocol, microServiceName, schemaID, operationID)
faultStruct.Abort.HTTPStatus = config.GetAbortStatus(protocol, microServiceName, schemaID, operationID)
faultStruct.Delay.Percent = config.GetDelayPercent(protocol, microServiceName, schemaID, operationID)
faultStruct.Delay.FixedDelay = config.GetFixedDelay(protocol, microServiceName, schemaID, operationID)
return faultStruct
}