Skip to content

Commit

Permalink
make face load balancer more atomic, not to get spikes when face free (
Browse files Browse the repository at this point in the history
  • Loading branch information
ice-cronus authored Jun 26, 2024
1 parent d7de0f3 commit 1864588
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 19 deletions.
6 changes: 6 additions & 0 deletions cmd/eskimo-hut/api/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,12 @@ const docTemplate = `{
"description": "the kyc steps you wish to skip",
"name": "skipKYCSteps",
"in": "query"
},
{
"type": "integer",
"description": "the kyc step which would be next",
"name": "nextKYCStep",
"in": "query"
}
],
"responses": {
Expand Down
6 changes: 6 additions & 0 deletions cmd/eskimo-hut/api/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,12 @@
"description": "the kyc steps you wish to skip",
"name": "skipKYCSteps",
"in": "query"
},
{
"type": "integer",
"description": "the kyc step which would be next",
"name": "nextKYCStep",
"in": "query"
}
],
"responses": {
Expand Down
4 changes: 4 additions & 0 deletions cmd/eskimo-hut/api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,10 @@ paths:
type: integer
name: skipKYCSteps
type: array
- description: the kyc step which would be next
in: query
name: nextKYCStep
type: integer
produces:
- application/json
responses:
Expand Down
1 change: 1 addition & 0 deletions cmd/eskimo-hut/kyc.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ func validateVerifySocialKYCStep(req *server.Request[kycsocial.VerificationMetad
// @Param X-Account-Metadata header string false "Insert your metadata token" default(<Add metadata token here>)
// @Param userId path string true "ID of the user"
// @Param skipKYCSteps query []int false "the kyc steps you wish to skip" collectionFormat(multi)
// @Param nextKYCStep query int false "the kyc step which would be next"
// @Success 200 {object} User
// @Failure 400 {object} server.ErrorResponse "if validations fail"
// @Failure 401 {object} server.ErrorResponse "if not authorized"
Expand Down
13 changes: 5 additions & 8 deletions kyc/face/face.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func New(ctx context.Context, usersRep UserRepository) Client {
cfg.UnexpectedErrorsAllowed = 5
}
db := storage.MustConnect(ctx, ddl, applicationYamlKey)
cl := &client{client: threedivi.New3Divi(usersRep, &cfg.ThreeDiVi), cfg: cfg, db: db}
cl := &client{client: threedivi.New3Divi(ctx, usersRep, &cfg.ThreeDiVi), cfg: cfg, db: db}
go cl.clearErrs(ctx)

return cl
Expand Down Expand Up @@ -56,19 +56,16 @@ func (c *client) CheckStatus(ctx context.Context, user *users.User, nextKYCStep
}
}
}
//nolint:nestif // .
if !hasResult || nextKYCStep == users.LivenessDetectionKYCStep {
availabilityErr := c.client.Available(ctx)
availabilityErr := c.client.Available(ctx, userWasPreviouslyForwardedToFaceKYC)
if availabilityErr == nil {
kycFaceAvailable = true
if fErr := c.saveUserForwarded(ctx, user.ID); fErr != nil {
return false, errors.Wrapf(fErr, "failed ")
}
} else {
if !errors.Is(availabilityErr, internal.ErrNotAvailable) {
c.unexpectedErrors.Add(1)
}
log.Error(errors.Wrapf(err, "[unexpected]face auth is unavailable for userID %v KYCStep %v", user.ID, nextKYCStep))
} else if !errors.Is(availabilityErr, internal.ErrNotAvailable) {
c.unexpectedErrors.Add(1)
log.Error(errors.Wrapf(availabilityErr, "[unexpected]face auth is unavailable for userID %v KYCStep %v", user.ID, nextKYCStep))
}
}

Expand Down
2 changes: 1 addition & 1 deletion kyc/face/internal/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

type (
Client interface {
Available(ctx context.Context) error
Available(ctx context.Context, userWasPreviouslyForwardedToFaceKYC bool) error
CheckAndUpdateStatus(ctx context.Context, user *users.User) (hasFaceKYCResult bool, err error)
Reset(ctx context.Context, user *users.User, fetchState bool) error
}
Expand Down
6 changes: 4 additions & 2 deletions kyc/face/internal/threedivi/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package threedivi

import (
"sync/atomic"
stdlibtime "time"

"github.com/pkg/errors"
Expand All @@ -12,8 +13,9 @@ import (

type (
threeDivi struct {
users internal.UserRepository
cfg *Config
users internal.UserRepository
cfg *Config
loadBalancedUsersCount atomic.Uint64
}
Config struct {
ThreeDiVi struct {
Expand Down
38 changes: 30 additions & 8 deletions kyc/face/internal/threedivi/threedivi.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func init() { //nolint:gochecknoinits // It's the only way to tweak the client.
req.DefaultClient().GetClient().Timeout = requestDeadline
}

func New3Divi(usersRepository internal.UserRepository, cfg *Config) internal.Client {
func New3Divi(ctx context.Context, usersRepository internal.UserRepository, cfg *Config) internal.Client {
if cfg.ThreeDiVi.BAFHost == "" {
log.Panic(errors.Errorf("no baf-host for 3divi integration"))
}
Expand All @@ -40,13 +40,16 @@ func New3Divi(usersRepository internal.UserRepository, cfg *Config) internal.Cli
}
cfg.ThreeDiVi.BAFHost, _ = strings.CutSuffix(cfg.ThreeDiVi.BAFHost, "/")

return &threeDivi{
tdv := &threeDivi{
users: usersRepository,
cfg: cfg,
}
go tdv.clearUsers(ctx)

return tdv
}

func (t *threeDivi) Available(ctx context.Context) error {
func (t *threeDivi) Available(ctx context.Context, userWasPreviouslyForwardedToFaceKYC bool) error {
if t.cfg.ThreeDiVi.AvailabilityURL == "" {
return nil
}
Expand Down Expand Up @@ -74,20 +77,39 @@ func (t *threeDivi) Available(ctx context.Context) error {
} else if data, err2 := resp.ToBytes(); err2 != nil {
return errors.Wrapf(err2, "failed to read body of availability of face auth")
} else { //nolint:revive // .
return t.isAvailable(data)
return t.isAvailable(data, userWasPreviouslyForwardedToFaceKYC)
}
}

func (t *threeDivi) isAvailable(data []byte) error {
//nolint:revive // .
func (t *threeDivi) isAvailable(data []byte, userWasPreviouslyForwardedToFaceKYC bool) error {
activeUsers, cErr := t.activeUsers(data)
if cErr != nil {
return errors.Wrapf(cErr, "failed to parse metrics of availability of face auth")
}
if activeUsers+1 > t.cfg.ThreeDiVi.ConcurrentUsers {
return internal.ErrNotAvailable
if int64(t.cfg.ThreeDiVi.ConcurrentUsers)-(int64(activeUsers)+int64(t.loadBalancedUsersCount.Load())) >= 1 {
if !userWasPreviouslyForwardedToFaceKYC {
t.loadBalancedUsersCount.Add(1)
}

return nil
}

return nil
return internal.ErrNotAvailable
}

func (t *threeDivi) clearUsers(ctx context.Context) {
ticker := stdlibtime.NewTicker(1 * stdlibtime.Minute)
defer ticker.Stop()

for {
select {
case <-ticker.C:
t.loadBalancedUsersCount.Store(0)
case <-ctx.Done():
return
}
}
}

func (*threeDivi) activeUsers(data []byte) (int, error) {
Expand Down

0 comments on commit 1864588

Please sign in to comment.