Skip to content

Commit bb108e5

Browse files
authored
Add support for comma-separated URLs (#1364)
* Add support for comma-separated URLs * Fix test * Minor fix
1 parent 061c6b4 commit bb108e5

File tree

3 files changed

+55
-34
lines changed

3 files changed

+55
-34
lines changed

schemaregistry/internal/client_config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222

2323
// ClientConfig is used to pass multiple configuration options to the Schema Registry client.
2424
type ClientConfig struct {
25-
// SchemaRegistryURL determines the URL of Schema Registry.
25+
// SchemaRegistryURL is a comma-space separated list of URLs for the Schema Registry.
2626
SchemaRegistryURL string
2727

2828
// BasicAuthUserInfo specifies the user info in the form of {username}:{password}.

schemaregistry/internal/rest_service.go

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func NewRequest(method string, endpoint string, body interface{}, arguments ...i
112112

113113
// RestService represents a REST client
114114
type RestService struct {
115-
url *url.URL
115+
urls []*url.URL
116116
headers http.Header
117117
maxRetries int
118118
retriesWaitMs int
@@ -124,21 +124,22 @@ type RestService struct {
124124
// NewRestService returns a new REST client for the Confluent Schema Registry
125125
func NewRestService(conf *ClientConfig) (*RestService, error) {
126126
urlConf := conf.SchemaRegistryURL
127-
u, err := url.Parse(urlConf)
128-
129-
if err != nil {
130-
return nil, err
127+
urlStrs := strings.Split(urlConf, ",")
128+
urls := make([]*url.URL, len(urlStrs))
129+
for i, urlStr := range urlStrs {
130+
u, err := url.Parse(strings.TrimSpace(urlStr))
131+
if err != nil {
132+
return nil, err
133+
}
134+
urls[i] = u
131135
}
132136

133-
headers, err := NewAuthHeader(u, conf)
137+
headers, err := NewAuthHeader(urls[0], conf)
134138
if err != nil {
135139
return nil, err
136140
}
137141

138142
headers.Add("Content-Type", "application/vnd.schemaregistry.v1+json")
139-
if err != nil {
140-
return nil, err
141-
}
142143

143144
if conf.HTTPClient == nil {
144145
transport, err := configureTransport(conf)
@@ -155,7 +156,7 @@ func NewRestService(conf *ClientConfig) (*RestService, error) {
155156
}
156157

157158
return &RestService{
158-
url: u,
159+
urls: urls,
159160
headers: headers,
160161
maxRetries: conf.MaxRetries,
161162
retriesWaitMs: conf.RetriesWaitMs,
@@ -337,19 +338,51 @@ func NewAuthHeader(service *url.URL, conf *ClientConfig) (http.Header, error) {
337338
return header, err
338339
}
339340

340-
// HandleRequest sends a HTTP(S) request to the Schema Registry, placing results into the response object
341+
// HandleRequest sends a request to the Schema Registry, iterating over the list of URLs
341342
func (rs *RestService) HandleRequest(request *API, response interface{}) error {
342-
urlPath := path.Join(rs.url.Path, fmt.Sprintf(request.endpoint, request.arguments...))
343-
endpoint, err := rs.url.Parse(urlPath)
344-
if err != nil {
343+
var resp *http.Response
344+
var err error
345+
for i, u := range rs.urls {
346+
resp, err = rs.HandleHTTPRequest(u, request)
347+
if err != nil {
348+
if i == len(rs.urls)-1 {
349+
return err
350+
}
351+
continue
352+
}
353+
if isSuccess(resp.StatusCode) || !isRetriable(resp.StatusCode) || i >= rs.maxRetries {
354+
break
355+
}
356+
}
357+
defer resp.Body.Close()
358+
if isSuccess(resp.StatusCode) {
359+
if err = json.NewDecoder(resp.Body).Decode(response); err != nil {
360+
return err
361+
}
362+
return nil
363+
}
364+
365+
var failure rest.Error
366+
if err = json.NewDecoder(resp.Body).Decode(&failure); err != nil {
345367
return err
346368
}
347369

370+
return &failure
371+
}
372+
373+
// HandleHTTPRequest sends a HTTP(S) request to the Schema Registry, placing results into the response object
374+
func (rs *RestService) HandleHTTPRequest(url *url.URL, request *API) (*http.Response, error) {
375+
urlPath := path.Join(url.Path, fmt.Sprintf(request.endpoint, request.arguments...))
376+
endpoint, err := url.Parse(urlPath)
377+
if err != nil {
378+
return nil, err
379+
}
380+
348381
var readCloser io.ReadCloser
349382
if request.body != nil {
350383
outbuf, err := json.Marshal(request.body)
351384
if err != nil {
352-
return err
385+
return nil, err
353386
}
354387
readCloser = ioutil.NopCloser(bytes.NewBuffer(outbuf))
355388
}
@@ -365,30 +398,16 @@ func (rs *RestService) HandleRequest(request *API, response interface{}) error {
365398
for i := 0; i < rs.maxRetries+1; i++ {
366399
resp, err = rs.Do(req)
367400
if err != nil {
368-
return err
401+
return nil, err
369402
}
370403

371404
if isSuccess(resp.StatusCode) || !isRetriable(resp.StatusCode) || i >= rs.maxRetries {
372-
break
405+
return resp, nil
373406
}
374407

375408
time.Sleep(rs.fullJitter(i))
376409
}
377-
378-
defer resp.Body.Close()
379-
if resp.StatusCode == 200 {
380-
if err = json.NewDecoder(resp.Body).Decode(response); err != nil {
381-
return err
382-
}
383-
return nil
384-
}
385-
386-
var failure rest.Error
387-
if err := json.NewDecoder(resp.Body).Decode(&failure); err != nil {
388-
return err
389-
}
390-
391-
return &failure
410+
return nil, fmt.Errorf("failed to send request after %d retries", rs.maxRetries)
392411
}
393412

394413
func (rs *RestService) fullJitter(retriesAttempted int) time.Duration {

schemaregistry/serde/avrov2/avro_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,8 @@ func TestAvroSerdeWithCELFieldTransformDisable(t *testing.T) {
937937
OnFailure: nil,
938938
Disabled: &[]bool{true}[0],
939939
})
940+
ser.RuleRegistry = &registry
941+
940942
id, err := client.Register("topic1-value", info, false)
941943
serde.MaybeFail("Schema registration", err)
942944
if id <= 0 {
@@ -960,7 +962,7 @@ func TestAvroSerdeWithCELFieldTransformDisable(t *testing.T) {
960962
deser.MessageFactory = testMessageFactory
961963

962964
newobj, err := deser.Deserialize("topic1", bytes)
963-
serde.MaybeFail("deserialization", err, serde.Expect(newobj, &obj))
965+
serde.MaybeFail("deserialization", err, serde.Expect(newobj.(*DemoSchema).StringField, "hi"))
964966
}
965967

966968
func TestAvroSerdeWithCELFieldTransform(t *testing.T) {

0 commit comments

Comments
 (0)