Skip to content

refactor: used a common http client for all the requests #1194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions client/httpClient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package client

import (
"net/http"
"razor/core"
"time"
)

var httpClient *http.Client
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DO not use global variables. Use a struct and implement methods. cc: @ashish10677


func InitHttpClient(httpTimeout int64) {
httpClient = &http.Client{
Timeout: time.Duration(httpTimeout) * time.Second,
Transport: &http.Transport{
MaxIdleConns: core.HTTPClientMaxIdleConns,
MaxIdleConnsPerHost: core.HTTPClientMaxIdleConnsPerHost,
},
}
}

func GetHttpClient() *http.Client {
return httpClient
}
1 change: 0 additions & 1 deletion cmd/config-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ func (*UtilsStruct) GetConfigData() (types.Configurations, error) {
config.RPCTimeout = rpcTimeout
utils.RPCTimeout = rpcTimeout
config.HTTPTimeout = httpTimeout
utils.HTTPTimeout = httpTimeout
config.LogFileMaxSize = logFileMaxSize
config.LogFileMaxBackups = logFileMaxBackups
config.LogFileMaxAge = logFileMaxAge
Expand Down
3 changes: 3 additions & 0 deletions cmd/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os/signal"
"path/filepath"
"razor/accounts"
clientPkg "razor/client"
"razor/core"
"razor/core/types"
"razor/logger"
Expand Down Expand Up @@ -88,6 +89,8 @@ func (*UtilsStruct) ExecuteVote(flagSet *pflag.FlagSet) {

account := types.Account{Address: address, Password: password}

clientPkg.InitHttpClient(config.HTTPTimeout)

cmdUtils.HandleExit()

err = cmdUtils.InitAssetCache(client)
Expand Down
5 changes: 5 additions & 0 deletions core/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,8 @@ var MaxIterations = 10000000

var AssetUpdateListenerInterval = 10
var AssetCacheExpiry = 5 * EpochLength

// Following are the constants used in custom http.Transport configuration for the common HTTP client that we use for all the requests

var HTTPClientMaxIdleConns = 15
var HTTPClientMaxIdleConnsPerHost = 5
16 changes: 7 additions & 9 deletions utils/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"net/http"
"razor/cache"
clientPkg "razor/client"
"razor/core"
"regexp"
"time"
Expand All @@ -20,10 +21,6 @@ import (
)

func GetDataFromAPI(dataSourceURLStruct types.DataSourceURL, localCache *cache.LocalCache) ([]byte, error) {
client := http.Client{
Timeout: time.Duration(HTTPTimeout) * time.Second,
}

cacheKey, err := generateCacheKey(dataSourceURLStruct.URL, dataSourceURLStruct.Body)
if err != nil {
log.Errorf("Error in generating cache key for API %s: %v", dataSourceURLStruct.URL, err)
Expand All @@ -36,7 +33,7 @@ func GetDataFromAPI(dataSourceURLStruct types.DataSourceURL, localCache *cache.L
return cachedData, nil
}

response, err := makeAPIRequest(client, dataSourceURLStruct)
response, err := makeAPIRequest(dataSourceURLStruct)
if err != nil {
return nil, err
}
Expand All @@ -46,7 +43,7 @@ func GetDataFromAPI(dataSourceURLStruct types.DataSourceURL, localCache *cache.L
return response, nil
}

func makeAPIRequest(client http.Client, dataSourceURLStruct types.DataSourceURL) ([]byte, error) {
func makeAPIRequest(dataSourceURLStruct types.DataSourceURL) ([]byte, error) {
var requestBody io.Reader // Using the broader io.Reader interface here

switch dataSourceURLStruct.Type {
Expand All @@ -68,7 +65,7 @@ func makeAPIRequest(client http.Client, dataSourceURLStruct types.DataSourceURL)
var response []byte
err := retry.Do(
func() error {
responseBody, err := ProcessRequest(client, dataSourceURLStruct, requestBody)
responseBody, err := ProcessRequest(dataSourceURLStruct, requestBody)
if err != nil {
log.Errorf("Error in processing %s request: %v", dataSourceURLStruct.Type, err)
return err
Expand Down Expand Up @@ -124,13 +121,14 @@ func addHeaderToRequest(request *http.Request, headerMap map[string]string) *htt
return request
}

func ProcessRequest(client http.Client, dataSourceURLStruct types.DataSourceURL, requestBody io.Reader) ([]byte, error) {
func ProcessRequest(dataSourceURLStruct types.DataSourceURL, requestBody io.Reader) ([]byte, error) {
httpClient := clientPkg.GetHttpClient()
request, err := http.NewRequest(dataSourceURLStruct.Type, dataSourceURLStruct.URL, requestBody)
if err != nil {
return nil, err
}
requestWithHeader := addHeaderToRequest(request, dataSourceURLStruct.Header)
response, err := client.Do(requestWithHeader)
response, err := httpClient.Do(requestWithHeader)
if err != nil {
log.Errorf("Error sending %s request URL %s: %v", dataSourceURLStruct.Type, dataSourceURLStruct.URL, err)
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions utils/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package utils
import (
"encoding/hex"
"razor/cache"
clientPkg "razor/client"
"razor/core/types"
"reflect"
"testing"
Expand Down Expand Up @@ -164,6 +165,7 @@ func TestGetDataFromAPI(t *testing.T) {
wantErr: true,
},
}
clientPkg.InitHttpClient(10)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
localCache := cache.NewLocalCache(time.Second * 10)
Expand Down
60 changes: 44 additions & 16 deletions utils/struct-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
"io"
"io/fs"
"math/big"
Expand All @@ -29,7 +30,6 @@ import (
)

var RPCTimeout int64
var HTTPTimeout int64

func StartRazor(optionsPackageStruct OptionsPackageStruct) Utils {
UtilsInterface = optionsPackageStruct.UtilsInterface
Expand Down Expand Up @@ -59,30 +59,58 @@ func StartRazor(optionsPackageStruct OptionsPackageStruct) Utils {
}

func InvokeFunctionWithTimeout(interfaceName interface{}, methodName string, args ...interface{}) []reflect.Value {
var functionCall []reflect.Value
var gotFunction = make(chan bool)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(RPCTimeout)*time.Second)
defer cancel()

resultChan := make(chan []reflect.Value)
errChan := make(chan error)

go func() {
defer close(resultChan)
defer close(errChan)

inputs := make([]reflect.Value, len(args))
for i := range args {
inputs[i] = reflect.ValueOf(args[i])
for i, arg := range args {
inputs[i] = reflect.ValueOf(arg)
}
log.Debug("Blockchain function: ", methodName)
functionCall = reflect.ValueOf(interfaceName).MethodByName(methodName).Call(inputs)
gotFunction <- true
}()
for {

log.Debug("Invoking blockchain function: ", methodName)

// Attempt to call the function
var result []reflect.Value
func() {
defer func() {
if r := recover(); r != nil {
errChan <- fmt.Errorf("panic during function call: %v", r)
}
}()
result = reflect.ValueOf(interfaceName).MethodByName(methodName).Call(inputs)
}()

// Send the result back or indicate the function has completed
select {
case <-ctx.Done():
log.Errorf("%s function timeout!", methodName)
log.Debug("Kindly check your connection")
return nil

case <-gotFunction:
return functionCall
// If the context is done, return the context-related error
errChan <- ctx.Err()
default:
resultChan <- result
}
}()

select {
case <-ctx.Done():
log.Errorf("%s function timeout!", methodName)
log.Debug("Please check your connection")
return nil

case err := <-errChan:
// Handle any errors that occurred during the function call
log.Errorf("Error:%v occurred in %s function!", err, methodName)
return nil

case result := <-resultChan:
// Function completed successfully
return result
}
}

Expand Down