Skip to content

Commit

Permalink
Merge pull request #550 from LerianStudio/feature/MIDAZ-549
Browse files Browse the repository at this point in the history
Feature/MIDAZ-549
  • Loading branch information
MartinezAvellan authored Feb 26, 2025
2 parents bf68292 + 681589e commit e8d94ed
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 87 deletions.
112 changes: 73 additions & 39 deletions components/transaction/internal/adapters/redis/consumer.redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,52 +211,65 @@ func (rr *RedisConsumerRepository) LockBalanceRedis(ctx context.Context, key str
end
return {
ID = balance.ID,
Available = total,
OnHold = balance.OnHold,
Scale = scale,
Version = balance.Version + 1,
AccountType = balance.AccountType
AccountType = balance.AccountType,
AllowSending = balance.AllowSending,
AllowReceiving = balance.AllowReceiving,
AssetCode = balance.AssetCode,
AccountID = balance.AccountID,
}
end
local function main()
local ttl = 300
local key = KEYS[1]
local operation = ARGV[1]
local amount = {
Asset = ARGV[2],
Available = tonumber(ARGV[3]),
Scale = tonumber(ARGV[4])
}
local ttl = 3600
local key = KEYS[1]
local amount = {
Asset = ARGV[1],
Available = tonumber(ARGV[2]),
Scale = tonumber(ARGV[3])
}
local balance = {
ID = ARGV[5],
Available = tonumber(ARGV[6]),
OnHold = tonumber(ARGV[7]),
Scale = tonumber(ARGV[8]),
Version = tonumber(ARGV[9]),
AccountType = ARGV[10],
AllowSending = tonumber(ARGV[11]),
AllowReceiving = tonumber(ARGV[12]),
AssetCode = ARGV[13],
AccountID = ARGV[14],
}
local currentValue = redis.call("GET", key)
if not currentValue then
local balanceEncoded = cjson.encode(balance)
redis.call("SET", key, balanceEncoded, "EX", ttl)
else
balance = cjson.decode(currentValue)
end
local finalBalance = OperateBalances(amount, balance, operation)
if finalBalance.Available < 0 and finalBalance.AccountType ~= "external" then
return redis.error_reply("0018")
end
local finalBalanceEncoded = cjson.encode(finalBalance)
redis.call("SET", key, finalBalanceEncoded, "EX", ttl)
local balance = {
Available = tonumber(ARGV[4]),
OnHold = tonumber(ARGV[5]),
Scale = tonumber(ARGV[6]),
Version = tonumber(ARGV[7]),
AccountType = ARGV[8]
}
local operation = ARGV[9]
local currentValue = redis.call("GET", key)
if not currentValue then
local balanceEncoded = cjson.encode(balance)
redis.call("SET", key, balanceEncoded, "EX", ttl)
else
balance = cjson.decode(currentValue)
end
local finalBalance = OperateBalances(amount, balance, operation)
if finalBalance.Available < 0 and finalBalance.AccountType ~= "external" then
return redis.error_reply("0018")
local balanceEncoded = cjson.encode(balance)
return balanceEncoded
end
local finalBalanceEncoded = cjson.encode(finalBalance)
redis.call("SET", key, finalBalanceEncoded, "EX", ttl)
local balanceEncoded = cjson.encode(balance)
return balanceEncoded
return main()
`)

rds, err := rr.conn.GetClient(ctx)
Expand All @@ -268,16 +281,31 @@ func (rr *RedisConsumerRepository) LockBalanceRedis(ctx context.Context, key str
return nil, err
}

allowSending := 0
if balance.AllowSending {
allowSending = 1
}

allowReceiving := 0
if balance.AllowReceiving {
allowReceiving = 1
}

args := []any{
operation,
amount.Asset,
strconv.FormatInt(amount.Value, 10),
strconv.FormatInt(amount.Scale, 10),
balance.ID,
strconv.FormatInt(balance.Available, 10),
strconv.FormatInt(balance.OnHold, 10),
strconv.FormatInt(balance.Scale, 10),
strconv.FormatInt(balance.Version, 10),
balance.AccountType,
operation,
allowSending,
allowReceiving,
balance.AssetCode,
balance.AccountID,
}

result, err := script.Run(ctx, rds, []string{key}, args).Result()
Expand All @@ -296,7 +324,7 @@ func (rr *RedisConsumerRepository) LockBalanceRedis(ctx context.Context, key str
logger.Infof("result type: %T", result)
logger.Infof("result value: %v", result)

var b mmodel.Balance
b := mmodel.BalanceRedis{}

var balanceJSON string
switch v := result.(type) {
Expand All @@ -314,15 +342,21 @@ func (rr *RedisConsumerRepository) LockBalanceRedis(ctx context.Context, key str
if err := json.Unmarshal([]byte(balanceJSON), &b); err != nil {
mopentelemetry.HandleSpanError(&span, "Error to Deserialization json", err)

logger.Fatalf("Error to Deserialization json: %v", err)
logger.Errorf("Error to Deserialization json: %v", err)

return nil, err
}

balance.ID = b.ID
balance.AccountID = b.AccountID
balance.Available = b.Available
balance.OnHold = b.OnHold
balance.Scale = b.Scale
balance.Version = b.Version
balance.AccountType = b.AccountType
balance.AllowSending = b.AllowSending == 1
balance.AllowReceiving = b.AllowReceiving == 1
balance.AssetCode = b.AssetCode

return &balance, nil
}
73 changes: 67 additions & 6 deletions components/transaction/internal/services/query/get-balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package query

import (
"context"
"encoding/json"
"github.com/LerianStudio/midaz/pkg"
"github.com/LerianStudio/midaz/pkg/constant"
goldModel "github.com/LerianStudio/midaz/pkg/gold/transaction/model"
Expand All @@ -10,28 +11,33 @@ import (
"github.com/google/uuid"
)

// GetBalances methods responsible to get balances.
// GetBalances methods responsible to get balances from database.
func (uc *UseCase) GetBalances(ctx context.Context, organizationID, ledgerID uuid.UUID, validate *goldModel.Responses) ([]*mmodel.Balance, error) {
tracer := pkg.NewTracerFromContext(ctx)
logger := pkg.NewLoggerFromContext(ctx)

ctx, span := tracer.Start(ctx, "query.get_balances")
ctx, span := tracer.Start(ctx, "usecase.get_balances")
defer span.End()

var ids []uuid.UUID

var aliases []string

for _, item := range validate.Aliases {
balances := make([]*mmodel.Balance, 0)

balancesRedis, newValidateAliases := uc.ValidateIfBalanceExistsOnRedis(ctx, organizationID, ledgerID, validate.Aliases)
if len(balancesRedis) > 0 {
balances = append(balances, balancesRedis...)
}

for _, item := range newValidateAliases {
if pkg.IsUUID(item) {
ids = append(ids, uuid.MustParse(item))
} else {
aliases = append(aliases, item)
}
}

balances := make([]*mmodel.Balance, 0)

if len(ids) > 0 {
balancesByIDs, err := uc.BalanceRepo.ListByAccountIDs(ctx, organizationID, ledgerID, ids)
if err != nil {
Expand Down Expand Up @@ -76,11 +82,64 @@ func (uc *UseCase) GetBalances(ctx context.Context, organizationID, ledgerID uui
return balances, nil
}

// ValidateIfBalanceExistsOnRedis func that validate if balance exists on redis before to get on database.
func (uc *UseCase) ValidateIfBalanceExistsOnRedis(ctx context.Context, organizationID, ledgerID uuid.UUID, aliases []string) ([]*mmodel.Balance, []string) {
tracer := pkg.NewTracerFromContext(ctx)
logger := pkg.NewLoggerFromContext(ctx)

ctx, span := tracer.Start(ctx, "usecase.validate_if_balance_exists_on_redis")
defer span.End()

logger.Infof("Checking if balances exists on redis")

newBalances := make([]*mmodel.Balance, 0)

newAliases := make([]string, 0)

for _, alias := range aliases {
internalKey := pkg.LockInternalKey(organizationID, ledgerID, alias)

value, _ := uc.RedisRepo.Get(ctx, internalKey)
if value != "" {
b := mmodel.BalanceRedis{}

if err := json.Unmarshal([]byte(value), &b); err != nil {
mopentelemetry.HandleSpanError(&span, "Error to Deserialization json", err)

logger.Warnf("Error to Deserialization json: %v", err)

continue
}

newBalances = append(newBalances, &mmodel.Balance{
ID: b.ID,
AccountID: b.AccountID,
OrganizationID: organizationID.String(),
LedgerID: ledgerID.String(),
Alias: alias,
Available: b.Available,
OnHold: b.OnHold,
Scale: b.Scale,
Version: b.Version,
AccountType: b.AccountType,
AllowSending: b.AllowSending == 1,
AllowReceiving: b.AllowReceiving == 1,
AssetCode: b.AssetCode,
})
} else {
newAliases = append(newAliases, alias)
}
}

return newBalances, newAliases
}

// GetAccountAndLock func responsible to integrate core business logic to redis.
func (uc *UseCase) GetAccountAndLock(ctx context.Context, organizationID, ledgerID uuid.UUID, validate *goldModel.Responses, balances []*mmodel.Balance) ([]*mmodel.Balance, error) {
logger := pkg.NewLoggerFromContext(ctx)
tracer := pkg.NewTracerFromContext(ctx)

ctx, span := tracer.Start(ctx, "query.get_account_and_lock")
ctx, span := tracer.Start(ctx, "usecase.get_account_and_lock")
defer span.End()

newBalances := make([]*mmodel.Balance, 0)
Expand Down Expand Up @@ -115,6 +174,8 @@ func (uc *UseCase) GetAccountAndLock(ctx context.Context, organizationID, ledger
return nil, err
}

b.Alias = balance.Alias

newBalances = append(newBalances, b)
}

Expand Down
24 changes: 10 additions & 14 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ require (
github.com/Masterminds/squirrel v1.5.4
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
github.com/antlr4-go/antlr/v4 v4.13.1
github.com/casdoor/casdoor-go-sdk v1.4.0
github.com/charmbracelet/bubbles v0.20.0
github.com/charmbracelet/bubbletea v1.3.3
github.com/charmbracelet/bubbletea v1.3.4
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/gofiber/fiber/v2 v2.52.6
Expand All @@ -23,14 +22,13 @@ require (
github.com/pelletier/go-toml/v2 v2.2.3
github.com/pkg/errors v0.9.1
github.com/rabbitmq/amqp091-go v1.10.0
github.com/redis/go-redis/v9 v9.7.0
github.com/redis/go-redis/v9 v9.7.1
github.com/rodaine/table v1.3.0
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/stretchr/testify v1.10.0
github.com/swaggo/fiber-swagger v1.3.0
github.com/swaggo/swag v1.16.4
github.com/transparency-dev/merkle v0.0.2
go.mongodb.org/mongo-driver v1.17.2
go.mongodb.org/mongo-driver v1.17.3
go.opentelemetry.io/contrib/bridges/otelzap v0.9.0
go.opentelemetry.io/otel v1.34.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.10.0
Expand Down Expand Up @@ -69,7 +67,6 @@ require (
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
Expand All @@ -81,23 +78,22 @@ require (
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/swaggo/files v1.0.1 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.9.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/oauth2 v0.26.0 // indirect
golang.org/x/tools v0.30.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 // indirect
)

require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/fatih/color v1.18.0
github.com/goccy/go-json v0.10.5 // indirect
github.com/golang/snappy v0.0.4 // indirect
Expand All @@ -120,8 +116,8 @@ require (
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/exp v0.0.0-20250215185904-eff6e970281f // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/text v0.22.0
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
Expand All @@ -135,7 +131,7 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang-migrate/migrate/v4 v4.18.2
github.com/google/uuid v1.6.0
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/lestrrat-go/jwx v1.2.30
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
Expand Down
Loading

0 comments on commit e8d94ed

Please sign in to comment.