Skip to content
Merged
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
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.24.x', '1.25.x', 'stable']

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

- name: Cache Go modules
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.go-version }}-

- name: Install dependencies
run: make setup

- name: Build and test
run: make test

- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
file: coverage.out
format: golang
31 changes: 31 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: "2"
run:
tests: true
linters:
default: none
enable:
- govet
- ineffassign
- staticcheck
- unused
- modernize
exclusions:
generated: lax
paths:
- vendor
- third_party$
- builtin$
- examples/
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofmt
exclusions:
generated: lax
paths:
- vendor
- third_party$
- builtin$
- examples/
10 changes: 0 additions & 10 deletions .travis.yml

This file was deleted.

22 changes: 8 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,33 +1,27 @@
.PHONYthub.com/mattn/goveralls: all
all: build test coverage
.PHONY: all
all: build test

ALL_PACKAGES=$(shell go list ./... | grep -v "vendor")

setup:
mkdir -p $(GOPATH)/bin
go get -u golang.org/x/lint/golint
go get github.com/mattn/goveralls
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0
go install github.com/mattn/goveralls@v0.0.12

compile:
mkdir -p out/
go build -race ./...

build: compile fmt vet lint
build: compile fmt lint

fmt:
go fmt ./...

vet:
go vet ./...

lint:
golint -set_exit_status $(ALL_PACKAGES)

test: fmt vet build
ENVIRONMENT=test go test -race ./...
golangci-lint run ./...

coverage:
ENVIRONMENT=test goveralls -service=travis-ci
test: fmt build
ENVIRONMENT=test go test -race -covermode=atomic -coverprofile=coverage.out ./...

test-cover-html:
@echo "mode: count" > coverage-all.out
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<p align="center"><img src="doc/heimdall-logo.png" width="360"></p>
<p align="center">
<a href="https://travis-ci.com/gojek/heimdall"><img src="https://travis-ci.com/gojek/heimdall.svg?branch=master" alt="Build Status"></img></a>
<a href="https://github.com/gojek/heimdall/actions"><img src="https://github.com/gojek/heimdall/actions/workflows/ci.yml/badge.svg" alt="Build Status"></img></a>
<a href="https://goreportcard.com/report/github.com/gojek/heimdall"><img src="https://goreportcard.com/badge/github.com/gojek/heimdall"></img></a>
<a href="https://golangci.com"><img src="https://golangci.com/badges/github.com/gojek/heimdall.svg"></img></a>
<a href="https://coveralls.io/github/gojek/heimdall?branch=master"><img src="https://coveralls.io/repos/github/gojek/heimdall/badge.svg?branch=master"></img></a>
Expand Down
10 changes: 3 additions & 7 deletions backoff.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package heimdall

import (
"math"
"math/rand"
"math/rand/v2"
"time"
)

Expand All @@ -16,10 +16,6 @@ type constantBackoff struct {
maximumJitterInterval int64
}

func init() {
rand.Seed(time.Now().UnixNano())
}

// NewConstantBackoff returns an instance of ConstantBackoff
func NewConstantBackoff(backoffInterval, maximumJitterInterval time.Duration) Backoff {
// protect against panic when generating random jitter
Expand All @@ -35,7 +31,7 @@ func NewConstantBackoff(backoffInterval, maximumJitterInterval time.Duration) Ba

// Next returns next time for retrying operation with constant strategy
func (cb *constantBackoff) Next(retry int) time.Duration {
return (time.Duration(cb.backoffInterval) * time.Millisecond) + (time.Duration(rand.Int63n(cb.maximumJitterInterval+1)) * time.Millisecond)
return (time.Duration(cb.backoffInterval) * time.Millisecond) + (time.Duration(rand.Int64N(cb.maximumJitterInterval+1)) * time.Millisecond)
}

type exponentialBackoff struct {
Expand Down Expand Up @@ -65,5 +61,5 @@ func (eb *exponentialBackoff) Next(retry int) time.Duration {
if retry < 0 {
retry = 0
}
return time.Duration(math.Min(eb.initialTimeout*math.Pow(eb.exponentFactor, float64(retry)), eb.maxTimeout)+float64(rand.Int63n(eb.maximumJitterInterval+1))) * time.Millisecond
return time.Duration(math.Min(eb.initialTimeout*math.Pow(eb.exponentFactor, float64(retry)), eb.maxTimeout)+float64(rand.Int64N(eb.maximumJitterInterval+1))) * time.Millisecond
}
12 changes: 6 additions & 6 deletions backoff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,21 @@ func TestExponentialBackoffWhenRetryIsLessThanZero(t *testing.T) {

func TestExponentialBackoffJitter0(t *testing.T) {
exponentialBackoff := NewExponentialBackoff(100*time.Millisecond, 1000*time.Millisecond, 2.0, 0*time.Millisecond)
for i := 0; i < 10000; i++ {
for range 10000 {
assert.Equal(t, 200*time.Millisecond, exponentialBackoff.Next(1))
}
}

func TestExponentialBackoffJitter1(t *testing.T) {
exponentialBackoff := NewExponentialBackoff(100*time.Millisecond, 1000*time.Millisecond, 2.0, 1*time.Millisecond)
for i := 0; i < 10000; i++ {
for range 10000 {
assert.True(t, 200*time.Millisecond <= exponentialBackoff.Next(1) && exponentialBackoff.Next(1) <= 201*time.Millisecond)
}
}

func TestExponentialBackoffJitter50(t *testing.T) {
exponentialBackoff := NewExponentialBackoff(100*time.Millisecond, 1000*time.Millisecond, 2.0, 50*time.Millisecond)
for i := 0; i < 10000; i++ {
for range 10000 {
assert.True(t, 200*time.Millisecond <= exponentialBackoff.Next(1) && exponentialBackoff.Next(1) <= 250*time.Millisecond)
}
}
Expand Down Expand Up @@ -90,21 +90,21 @@ func TestConstantBackoffWhenRetryIsLessThanZero(t *testing.T) {

func TestConstantBackoffJitter0(t *testing.T) {
constantBackoff := NewConstantBackoff(100*time.Millisecond, 0*time.Millisecond)
for i := 0; i < 10000; i++ {
for i := range 10000 {
assert.Equal(t, 100*time.Millisecond, constantBackoff.Next(i))
}
}

func TestConstantBackoffJitter1(t *testing.T) {
constantBackoff := NewConstantBackoff(100*time.Millisecond, 1*time.Millisecond)
for i := 0; i < 10000; i++ {
for i := range 10000 {
assert.True(t, 100*time.Millisecond <= constantBackoff.Next(i) && constantBackoff.Next(1) <= 101*time.Millisecond)
}
}

func TestConstantBackoffJitter50(t *testing.T) {
constantBackoff := NewConstantBackoff(100*time.Millisecond, 50*time.Millisecond)
for i := 0; i < 10000; i++ {
for i := range 10000 {
assert.True(t, 100*time.Millisecond <= constantBackoff.Next(i) && constantBackoff.Next(1) <= 150*time.Millisecond)
}
}
10 changes: 5 additions & 5 deletions examples/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package examples

import (
"fmt"
"io/ioutil"
"io"
"net/http"
"time"

Expand Down Expand Up @@ -34,7 +34,7 @@ func httpClientUsage() error {

defer response.Body.Close()

respBody, err := ioutil.ReadAll(response.Body)
respBody, err := io.ReadAll(response.Body)
if err != nil {
return errors.Wrap(err, "failed to read response body")
}
Expand Down Expand Up @@ -63,7 +63,7 @@ func hystrixClientUsage() error {

defer response.Body.Close()

respBody, err := ioutil.ReadAll(response.Body)
respBody, err := io.ReadAll(response.Body)
if err != nil {
return errors.Wrap(err, "failed to read response body")
}
Expand Down Expand Up @@ -102,7 +102,7 @@ func customHTTPClientUsage() error {

defer response.Body.Close()

respBody, err := ioutil.ReadAll(response.Body)
respBody, err := io.ReadAll(response.Body)
if err != nil {
return errors.Wrap(err, "failed to read response body")
}
Expand Down Expand Up @@ -136,7 +136,7 @@ func customHystrixClientUsage() error {

defer response.Body.Close()

respBody, err := ioutil.ReadAll(response.Body)
respBody, err := io.ReadAll(response.Body)
if err != nil {
return errors.Wrap(err, "failed to read response body")
}
Expand Down
16 changes: 11 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
module github.com/gojek/heimdall/v7

go 1.14
go 1.24

require (
github.com/DataDog/datadog-go v3.7.1+incompatible // indirect
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c // indirect
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.11.1
)

require (
github.com/DataDog/datadog-go v3.7.1+incompatible // indirect
github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/objx v0.3.0 // indirect
github.com/stretchr/testify v1.3.0
github.com/stretchr/objx v0.5.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
15 changes: 8 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 h1:rFw4nCn9iMW+Vaj
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c h1:HIGF0r/56+7fuIZw2V4isE22MK6xpxWx7BbV8dJ290w=
github.com/cactus/go-statsd-client/statsd v0.0.0-20200423205355-cb0885a1018c/go.mod h1:l/bIBLeOl9eX+wxJAzxS4TveKRtAqlyDpHjhkfO0MEI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gojek/valkyrie v0.0.0-20180215180059-6aee720afcdf h1:5xRGbUdOmZKoDXkGx5evVLehuCMpuO1hl701bEQqXOM=
Expand All @@ -24,13 +22,16 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
15 changes: 7 additions & 8 deletions httpclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package httpclient
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"time"

Expand All @@ -14,12 +13,11 @@ import (

// Client is the http client implementation
type Client struct {
client heimdall.Doer

timeout time.Duration
retryCount int
client heimdall.Doer
retrier heimdall.Retriable
plugins []heimdall.Plugin
timeout time.Duration
retryCount int
}

const (
Expand Down Expand Up @@ -125,20 +123,21 @@ func (c *Client) Do(request *http.Request) (*http.Response, error) {
var bodyReader *bytes.Reader

if request.Body != nil {
reqData, err := ioutil.ReadAll(request.Body)
reqData, err := io.ReadAll(request.Body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(reqData)
request.Body = ioutil.NopCloser(bodyReader) // prevents closing the body between retries
request.Body = io.NopCloser(bodyReader) // prevents closing the body between retries
}

multiErr := &valkyrie.MultiError{}
var response *http.Response

for i := 0; i <= c.retryCount; i++ {
if response != nil {
response.Body.Close()
_, _ = io.Copy(io.Discard, response.Body)
_ = response.Body.Close()
}

c.reportRequestStart(request)
Expand Down
Loading
Loading