mirror of
https://github.com/elyby/chrly.git
synced 2024-12-23 13:40:11 +05:30
Merge branch 'worker_health_status'. Resolves #16
This commit is contained in:
commit
b0ba94751a
9
Gopkg.lock
generated
9
Gopkg.lock
generated
@ -39,6 +39,14 @@
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2e7c296138d042515eb2995fe58026eaef2c08f660a5f36584faecf34eea3cf0"
|
||||
name = "github.com/etherlabsio/healthcheck"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "dd3d2fd8c3f620a32b7f3cd9b4f0d2f7d0875ab1"
|
||||
version = "2.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9f1e571696860f2b4f8a241b43ce91c6085e7aaed849ccca53f590a4dc7b95bd"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
@ -311,6 +319,7 @@
|
||||
"github.com/SermoDigital/jose/crypto",
|
||||
"github.com/SermoDigital/jose/jws",
|
||||
"github.com/asaskevich/EventBus",
|
||||
"github.com/etherlabsio/healthcheck",
|
||||
"github.com/getsentry/raven-go",
|
||||
"github.com/gorilla/mux",
|
||||
"github.com/h2non/gock",
|
||||
|
@ -41,6 +41,10 @@ ignored = ["github.com/elyby/chrly"]
|
||||
source = "https://github.com/erickskrauch/EventBus.git"
|
||||
branch = "publish_nil_values"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/etherlabsio/healthcheck"
|
||||
version = "2.0.3"
|
||||
|
||||
# Testing dependencies
|
||||
|
||||
[[constraint]]
|
||||
|
@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/etherlabsio/healthcheck"
|
||||
"github.com/mono83/slf/wd"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@ -51,6 +53,22 @@ var workerCmd = &cobra.Command{
|
||||
Emitter: dispatcher,
|
||||
UUIDsProvider: uuidsProvider,
|
||||
}).CreateHandler()
|
||||
handler.Handle("/healthcheck", healthcheck.Handler(
|
||||
healthcheck.WithChecker(
|
||||
"mojang-batch-uuids-provider-response",
|
||||
eventsubscribers.MojangBatchUuidsProviderResponseChecker(
|
||||
dispatcher,
|
||||
viper.GetDuration("healthcheck.mojang_batch_uuids_provider_cool_down_duration"),
|
||||
),
|
||||
),
|
||||
healthcheck.WithChecker(
|
||||
"mojang-batch-uuids-provider-queue-length",
|
||||
eventsubscribers.MojangBatchUuidsProviderQueueLengthChecker(
|
||||
dispatcher,
|
||||
viper.GetInt("healthcheck.mojang_batch_uuids_provider_queue_length_limit"),
|
||||
),
|
||||
),
|
||||
)).Methods("GET")
|
||||
|
||||
finishChan := make(chan bool)
|
||||
go func() {
|
||||
@ -73,4 +91,6 @@ var workerCmd = &cobra.Command{
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(workerCmd)
|
||||
viper.SetDefault("healthcheck.mojang_batch_uuids_provider_cool_down_duration", time.Minute)
|
||||
viper.SetDefault("healthcheck.mojang_batch_uuids_provider_queue_length_limit", 50)
|
||||
}
|
||||
|
64
eventsubscribers/health_checkers.go
Normal file
64
eventsubscribers/health_checkers.go
Normal file
@ -0,0 +1,64 @@
|
||||
package eventsubscribers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/etherlabsio/healthcheck"
|
||||
|
||||
"github.com/elyby/chrly/api/mojang"
|
||||
)
|
||||
|
||||
func MojangBatchUuidsProviderResponseChecker(dispatcher Subscriber, resetDuration time.Duration) healthcheck.CheckerFunc {
|
||||
var mutex sync.Mutex
|
||||
var lastCallErr error
|
||||
var expireTimer *time.Timer
|
||||
dispatcher.Subscribe(
|
||||
"mojang_textures:batch_uuids_provider:result",
|
||||
func(usernames []string, profiles []*mojang.ProfileInfo, err error) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
lastCallErr = err
|
||||
if expireTimer != nil {
|
||||
expireTimer.Stop()
|
||||
}
|
||||
|
||||
expireTimer = time.AfterFunc(resetDuration, func() {
|
||||
mutex.Lock()
|
||||
lastCallErr = nil
|
||||
mutex.Unlock()
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
return func(ctx context.Context) error {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
return lastCallErr
|
||||
}
|
||||
}
|
||||
|
||||
func MojangBatchUuidsProviderQueueLengthChecker(dispatcher Subscriber, maxLength int) healthcheck.CheckerFunc {
|
||||
var mutex sync.Mutex
|
||||
queueLength := 0
|
||||
dispatcher.Subscribe("mojang_textures:batch_uuids_provider:round", func(usernames []string, tasksInQueue int) {
|
||||
mutex.Lock()
|
||||
queueLength = tasksInQueue
|
||||
mutex.Unlock()
|
||||
})
|
||||
|
||||
return func(ctx context.Context) error {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if queueLength < maxLength {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("the maximum number of tasks in the queue has been exceeded")
|
||||
}
|
||||
}
|
71
eventsubscribers/health_checkers_test.go
Normal file
71
eventsubscribers/health_checkers_test.go
Normal file
@ -0,0 +1,71 @@
|
||||
package eventsubscribers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/elyby/chrly/api/mojang"
|
||||
"github.com/elyby/chrly/bootstrap"
|
||||
)
|
||||
|
||||
func TestMojangBatchUuidsProviderChecker(t *testing.T) {
|
||||
t.Run("empty state", func(t *testing.T) {
|
||||
dispatcher := bootstrap.CreateEventDispatcher()
|
||||
checker := MojangBatchUuidsProviderResponseChecker(dispatcher, time.Millisecond)
|
||||
assert.Nil(t, checker(context.Background()))
|
||||
})
|
||||
|
||||
t.Run("when no error occurred", func(t *testing.T) {
|
||||
dispatcher := bootstrap.CreateEventDispatcher()
|
||||
checker := MojangBatchUuidsProviderResponseChecker(dispatcher, time.Millisecond)
|
||||
dispatcher.Emit("mojang_textures:batch_uuids_provider:result", []string{"username"}, []*mojang.ProfileInfo{}, nil)
|
||||
assert.Nil(t, checker(context.Background()))
|
||||
})
|
||||
|
||||
t.Run("when error occurred", func(t *testing.T) {
|
||||
dispatcher := bootstrap.CreateEventDispatcher()
|
||||
checker := MojangBatchUuidsProviderResponseChecker(dispatcher, time.Millisecond)
|
||||
err := errors.New("some error occurred")
|
||||
dispatcher.Emit("mojang_textures:batch_uuids_provider:result", []string{"username"}, nil, err)
|
||||
assert.Equal(t, err, checker(context.Background()))
|
||||
})
|
||||
|
||||
t.Run("should reset value after passed duration", func(t *testing.T) {
|
||||
dispatcher := bootstrap.CreateEventDispatcher()
|
||||
checker := MojangBatchUuidsProviderResponseChecker(dispatcher, 20*time.Millisecond)
|
||||
err := errors.New("some error occurred")
|
||||
dispatcher.Emit("mojang_textures:batch_uuids_provider:result", []string{"username"}, nil, err)
|
||||
assert.Equal(t, err, checker(context.Background()))
|
||||
time.Sleep(40 * time.Millisecond)
|
||||
assert.Nil(t, checker(context.Background()))
|
||||
})
|
||||
}
|
||||
|
||||
func TestMojangBatchUuidsProviderQueueLengthChecker(t *testing.T) {
|
||||
t.Run("empty state", func(t *testing.T) {
|
||||
dispatcher := bootstrap.CreateEventDispatcher()
|
||||
checker := MojangBatchUuidsProviderQueueLengthChecker(dispatcher, 10)
|
||||
assert.Nil(t, checker(context.Background()))
|
||||
})
|
||||
|
||||
t.Run("less than allowed limit", func(t *testing.T) {
|
||||
dispatcher := bootstrap.CreateEventDispatcher()
|
||||
checker := MojangBatchUuidsProviderQueueLengthChecker(dispatcher, 10)
|
||||
dispatcher.Emit("mojang_textures:batch_uuids_provider:round", []string{"username"}, 9)
|
||||
assert.Nil(t, checker(context.Background()))
|
||||
})
|
||||
|
||||
t.Run("greater than allowed limit", func(t *testing.T) {
|
||||
dispatcher := bootstrap.CreateEventDispatcher()
|
||||
checker := MojangBatchUuidsProviderQueueLengthChecker(dispatcher, 10)
|
||||
dispatcher.Emit("mojang_textures:batch_uuids_provider:round", []string{"username"}, 10)
|
||||
checkResult := checker(context.Background())
|
||||
if assert.Error(t, checkResult) {
|
||||
assert.Equal(t, "the maximum number of tasks in the queue has been exceeded", checkResult.Error())
|
||||
}
|
||||
})
|
||||
}
|
@ -111,12 +111,13 @@ func (ctx *BatchUuidsProvider) queueRound() {
|
||||
usernames = append(usernames, job.username)
|
||||
}
|
||||
|
||||
ctx.Emit("mojang_textures:batch_uuids_provider:round", usernames, queueSize - len(jobs))
|
||||
ctx.Emit("mojang_textures:batch_uuids_provider:round", usernames, queueSize-len(jobs))
|
||||
if len(usernames) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
profiles, err := usernamesToUuids(usernames)
|
||||
ctx.Emit("mojang_textures:batch_uuids_provider:result", usernames, profiles, err)
|
||||
for _, job := range jobs {
|
||||
go func(job *jobItem) {
|
||||
response := &jobResult{}
|
||||
|
@ -155,13 +155,16 @@ func TestBatchUuidsProvider(t *testing.T) {
|
||||
}
|
||||
|
||||
func (suite *batchUuidsProviderTestSuite) TestGetUuidForOneUsername() {
|
||||
expectedUsernames := []string{"username"}
|
||||
expectedResult := &mojang.ProfileInfo{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username"}
|
||||
expectedResponse := []*mojang.ProfileInfo{expectedResult}
|
||||
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username"}, 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", expectedUsernames, 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:result", expectedUsernames, expectedResponse, nil).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Once()
|
||||
|
||||
suite.MojangApi.On("UsernamesToUuids", []string{"username"}).Once().Return([]*mojang.ProfileInfo{expectedResult}, nil)
|
||||
suite.MojangApi.On("UsernamesToUuids", expectedUsernames).Once().Return([]*mojang.ProfileInfo{expectedResult}, nil)
|
||||
|
||||
resultChan := suite.GetUuidAsync("username")
|
||||
|
||||
@ -173,14 +176,17 @@ func (suite *batchUuidsProviderTestSuite) TestGetUuidForOneUsername() {
|
||||
}
|
||||
|
||||
func (suite *batchUuidsProviderTestSuite) TestGetUuidForTwoUsernames() {
|
||||
expectedUsernames := []string{"username1", "username2"}
|
||||
expectedResult1 := &mojang.ProfileInfo{Id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Name: "username1"}
|
||||
expectedResult2 := &mojang.ProfileInfo{Id: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Name: "username2"}
|
||||
expectedResponse := []*mojang.ProfileInfo{expectedResult1, expectedResult2}
|
||||
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username1", "username2"}, 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", expectedUsernames, 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:result", expectedUsernames, expectedResponse, nil).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Once()
|
||||
|
||||
suite.MojangApi.On("UsernamesToUuids", []string{"username1", "username2"}).Once().Return([]*mojang.ProfileInfo{
|
||||
suite.MojangApi.On("UsernamesToUuids", expectedUsernames).Once().Return([]*mojang.ProfileInfo{
|
||||
expectedResult1,
|
||||
expectedResult2,
|
||||
}, nil)
|
||||
@ -205,13 +211,18 @@ func (suite *batchUuidsProviderTestSuite) TestGetUuidForMoreThan10Usernames() {
|
||||
usernames[i] = randStr(8)
|
||||
}
|
||||
|
||||
// In this test we're not testing response, so always return an empty resultset
|
||||
expectedResponse := []*mojang.ProfileInfo{}
|
||||
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Twice()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", usernames[0:10], 2).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:result", usernames[0:10], expectedResponse, nil).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", usernames[10:12], 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:result", usernames[10:12], expectedResponse, nil).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Twice()
|
||||
|
||||
suite.MojangApi.On("UsernamesToUuids", usernames[0:10]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||
suite.MojangApi.On("UsernamesToUuids", usernames[10:12]).Once().Return([]*mojang.ProfileInfo{}, nil)
|
||||
suite.MojangApi.On("UsernamesToUuids", usernames[0:10]).Once().Return(expectedResponse, nil)
|
||||
suite.MojangApi.On("UsernamesToUuids", usernames[10:12]).Once().Return(expectedResponse, nil)
|
||||
|
||||
channels := make([]chan *batchUuidsProviderGetUuidResult, len(usernames))
|
||||
for i, username := range usernames {
|
||||
@ -229,6 +240,7 @@ func (suite *batchUuidsProviderTestSuite) TestGetUuidForMoreThan10Usernames() {
|
||||
func (suite *batchUuidsProviderTestSuite) TestDoNothingWhenNoTasks() {
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Times(3)
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username"}, 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:result", []string{"username"}, mock.Anything, nil).Once()
|
||||
var nilStringSlice []string
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", nilStringSlice, 0).Twice()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Times(3)
|
||||
@ -250,13 +262,16 @@ func (suite *batchUuidsProviderTestSuite) TestDoNothingWhenNoTasks() {
|
||||
}
|
||||
|
||||
func (suite *batchUuidsProviderTestSuite) TestGetUuidForTwoUsernamesWithAnError() {
|
||||
expectedUsernames := []string{"username1", "username2"}
|
||||
expectedError := &mojang.TooManyRequestsError{}
|
||||
var nilProfilesResponse []*mojang.ProfileInfo
|
||||
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:before_round").Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", []string{"username1", "username2"}, 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:round", expectedUsernames, 0).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:result", expectedUsernames, nilProfilesResponse, expectedError).Once()
|
||||
suite.Emitter.On("Emit", "mojang_textures:batch_uuids_provider:after_round").Once()
|
||||
|
||||
suite.MojangApi.On("UsernamesToUuids", []string{"username1", "username2"}).Once().Return(nil, expectedError)
|
||||
suite.MojangApi.On("UsernamesToUuids", expectedUsernames).Once().Return(nil, expectedError)
|
||||
|
||||
resultChan1 := suite.GetUuidAsync("username1")
|
||||
resultChan2 := suite.GetUuidAsync("username2")
|
||||
|
Loading…
Reference in New Issue
Block a user