18
18
package http
19
19
20
20
import (
21
+ "bytes"
22
+ "context"
23
+ "fmt"
21
24
"net/http"
22
- "net/url"
25
+ "strconv"
26
+ "strings"
23
27
"time"
24
28
25
29
"github.com/polarismesh/specification/source/go/api/v1/fault_tolerance"
@@ -30,14 +34,18 @@ import (
30
34
"github.com/polarismesh/polaris-go/pkg/plugin"
31
35
"github.com/polarismesh/polaris-go/pkg/plugin/common"
32
36
"github.com/polarismesh/polaris-go/pkg/plugin/healthcheck"
33
- "github.com/polarismesh/polaris-go/plugin/healthcheck/utils"
34
37
)
35
38
39
+ type HttpSender interface {
40
+ Do (req * http.Request ) (* http.Response , error )
41
+ }
42
+
36
43
// Detector TCP协议的实例健康探测器
37
44
type Detector struct {
38
45
* plugin.PluginBase
39
46
cfg * Config
40
47
timeout time.Duration
48
+ client HttpSender
41
49
}
42
50
43
51
// Type 插件类型
@@ -57,6 +65,7 @@ func (g *Detector) Init(ctx *plugin.InitContext) (err error) {
57
65
if cfgValue != nil {
58
66
g .cfg = cfgValue .(* Config )
59
67
}
68
+ g .client = & http.Client {}
60
69
g .timeout = ctx .Config .GetConsumer ().GetHealthCheck ().GetTimeout ()
61
70
return nil
62
71
}
@@ -67,15 +76,26 @@ func (g *Detector) Destroy() error {
67
76
}
68
77
69
78
// DetectInstance 探测服务实例健康
70
- func (g * Detector ) DetectInstance (ins model.Instance ) (result healthcheck.DetectResult , err error ) {
79
+ func (g * Detector ) DetectInstance (ins model.Instance , rule * fault_tolerance. FaultDetectRule ) (result healthcheck.DetectResult , err error ) {
71
80
start := time .Now ()
81
+ timeout := g .timeout
82
+ if rule != nil && rule .Protocol == fault_tolerance .FaultDetectRule_HTTP {
83
+ timeout = time .Duration (rule .GetTimeout ()) * time .Millisecond
84
+ }
85
+
86
+ ctx , cancel := context .WithTimeout (context .Background (), timeout )
87
+ defer cancel ()
72
88
// 得到Http address
73
- address := utils .GetAddressByInstance (ins )
74
- success := g .doHttpDetect (address )
89
+ detReq , err := g .generateHttpRequest (ctx , ins , rule )
90
+ if err != nil {
91
+ return nil , err
92
+ }
93
+ code , success := g .doHttpDetect (detReq , rule )
75
94
result = & healthcheck.DetectResultImp {
76
95
Success : success ,
77
96
DetectTime : start ,
78
97
DetectInstance : ins ,
98
+ Code : code ,
79
99
}
80
100
return result , nil
81
101
}
@@ -86,50 +106,66 @@ func (g *Detector) IsEnable(cfg config.Configuration) bool {
86
106
}
87
107
88
108
// doHttpDetect 执行一次健康探测逻辑
89
- func (g * Detector ) doHttpDetect (address string ) bool {
90
- c := & http.Client {
91
- Timeout : g .timeout ,
92
- }
93
- request := & http.Request {
94
- Method : http .MethodGet ,
95
- URL : & url.URL {
96
- Scheme : "http" ,
97
- Host : address ,
98
- Path : g .cfg .Path ,
99
- },
100
- }
101
- header := http.Header {}
102
- if len (g .cfg .Host ) > 0 {
103
- header .Add ("Host" , g .cfg .Host )
104
- }
105
- if len (g .cfg .RequestHeadersToAdd ) > 0 {
106
- for _ , requestHeader := range g .cfg .RequestHeadersToAdd {
107
- header .Add (requestHeader .Key , requestHeader .Value )
108
- }
109
- }
110
- if len (header ) > 0 {
111
- request .Header = header
112
- }
113
- resp , err := c .Do (request )
109
+ func (g * Detector ) doHttpDetect (detReq * http.Request , rule * fault_tolerance.FaultDetectRule ) (string , bool ) {
110
+ resp , err := g .client .Do (detReq )
114
111
if err != nil {
115
- log .GetDetectLogger ().Errorf ("[HealthCheck][http] fail to check %s , err is %v" , address , err )
116
- return false
112
+ log .GetDetectLogger ().Errorf ("[HealthCheck][http] fail to check %+v , err is %v" , detReq . URL , err )
113
+ return "" , false
117
114
}
118
115
defer resp .Body .Close ()
119
- code := resp .StatusCode
120
- for _ , statusCodeRange := range g .cfg .ExpectedStatuses {
121
- if code >= statusCodeRange .Start && code < statusCodeRange .End {
122
- return true
123
- }
116
+ if code := resp .StatusCode ; code >= 200 && code < 500 {
117
+ return strconv .Itoa (resp .StatusCode ), true
124
118
}
125
- return false
119
+ return strconv . Itoa ( resp . StatusCode ), false
126
120
}
127
121
128
122
// Protocol .
129
123
func (g * Detector ) Protocol () fault_tolerance.FaultDetectRule_Protocol {
130
124
return fault_tolerance .FaultDetectRule_HTTP
131
125
}
132
126
127
+ func (g * Detector ) generateHttpRequest (ctx context.Context , ins model.Instance , rule * fault_tolerance.FaultDetectRule ) (* http.Request , error ) {
128
+ var (
129
+ address string
130
+ customUrl = g .cfg .Path
131
+ port = ins .GetPort ()
132
+ )
133
+ header := http.Header {}
134
+ if rule == nil {
135
+ customUrl = strings .TrimPrefix (customUrl , "/" )
136
+ if len (g .cfg .Host ) > 0 {
137
+ header .Add ("Host" , g .cfg .Host )
138
+ }
139
+ if len (g .cfg .RequestHeadersToAdd ) > 0 {
140
+ for _ , requestHeader := range g .cfg .RequestHeadersToAdd {
141
+ header .Add (requestHeader .Key , requestHeader .Value )
142
+ }
143
+ }
144
+ } else {
145
+ if rule .GetPort () > 0 {
146
+ port = rule .Port
147
+ }
148
+ customUrl = rule .GetHttpConfig ().GetUrl ()
149
+ customUrl = strings .TrimPrefix (customUrl , "/" )
150
+ ruleHeaders := rule .GetHttpConfig ().GetHeaders ()
151
+ for i := range ruleHeaders {
152
+ header .Add (ruleHeaders [i ].Key , ruleHeaders [i ].Value )
153
+ }
154
+ }
155
+ address = fmt .Sprintf ("http://%s:%d/%s" , ins .GetHost (), port , customUrl )
156
+
157
+ request , err := http .NewRequestWithContext (ctx , rule .GetHttpConfig ().Method , address , bytes .NewBufferString (rule .HttpConfig .GetBody ()))
158
+ if err != nil {
159
+ log .GetDetectLogger ().Errorf ("[HealthCheck][http] fail to build request %+v, err is %v" , address , err )
160
+ return nil , err
161
+ }
162
+
163
+ if len (header ) > 0 {
164
+ request .Header = header
165
+ }
166
+ return request , nil
167
+ }
168
+
133
169
// init 注册插件信息
134
170
func init () {
135
171
plugin .RegisterConfigurablePlugin (& Detector {}, & Config {})
0 commit comments