11package currency
22
33import (
4+ "context"
45 "fmt"
56 "io"
67 "net/http"
@@ -16,6 +17,7 @@ import (
1617// RateConverter holds the currencies conversion rates dictionary
1718type RateConverter struct {
1819 httpClient httpClient
20+ httpTimeout time.Duration
1921 staleRatesThreshold time.Duration
2022 syncSourceURL string
2123 rates atomic.Value // Should only hold Rates struct
@@ -27,11 +29,13 @@ type RateConverter struct {
2729// NewRateConverter returns a new RateConverter
2830func NewRateConverter (
2931 httpClient httpClient ,
32+ httpTimeout time.Duration ,
3033 syncSourceURL string ,
3134 staleRatesThreshold time.Duration ,
3235) * RateConverter {
3336 return & RateConverter {
3437 httpClient : httpClient ,
38+ httpTimeout : httpTimeout ,
3539 staleRatesThreshold : staleRatesThreshold ,
3640 syncSourceURL : syncSourceURL ,
3741 rates : atomic.Value {},
@@ -43,7 +47,10 @@ func NewRateConverter(
4347
4448// fetch allows to retrieve the currencies rates from the syncSourceURL provided
4549func (rc * RateConverter ) fetch () (* Rates , error ) {
46- request , err := http .NewRequest ("GET" , rc .syncSourceURL , nil )
50+ ctx , cancel := context .WithTimeout (context .Background (), rc .httpTimeout )
51+ defer cancel ()
52+
53+ request , err := http .NewRequestWithContext (ctx , "GET" , rc .syncSourceURL , nil )
4754 if err != nil {
4855 return nil , err
4956 }
@@ -52,23 +59,29 @@ func (rc *RateConverter) fetch() (*Rates, error) {
5259 if err != nil {
5360 return nil , err
5461 }
62+ defer func () {
63+ // read the entire response body to ensure full connection reuse if there's an
64+ // invalid status code
65+ if _ , err := io .Copy (io .Discard , response .Body ); err != nil {
66+ glog .Errorf ("error draining conversion rates response body: %v" , err )
67+ }
68+ response .Body .Close ()
69+ }()
5570
5671 if response .StatusCode >= 400 {
57- message := fmt .Sprintf ("The currency rates request failed with status code %d" , response .StatusCode )
72+ message := fmt .Sprintf ("the currency rates request failed with status code %d" , response .StatusCode )
5873 return nil , & errortypes.BadServerResponse {Message : message }
5974 }
6075
61- defer response .Body .Close ()
62-
6376 bytesJSON , err := io .ReadAll (response .Body )
6477 if err != nil {
65- return nil , err
78+ return nil , fmt . Errorf ( "the currency rates request failed: %v" , err )
6679 }
6780
6881 updatedRates := & Rates {}
6982 err = jsonutil .UnmarshalValid (bytesJSON , updatedRates )
7083 if err != nil {
71- return nil , err
84+ return nil , fmt . Errorf ( "the currency rates request failed to parse json: %v" , err )
7285 }
7386
7487 return updatedRates , err
0 commit comments