Skip to content
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

Switch off node for a specific currency #446

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

sundayonah
Copy link
Collaborator

Description

This PR implements a feature allowing Paycrest/Aggregator users to switch off a provider’s node for a specific currency while keeping the provider available for other currencies.

Key Changes

  1. Schema Addition: Added a new ProviderCurrencyAvailability join table to track per-currency availability for providers, with fields
    provider_id, currency_id, and is_available.

  2. Profile Update Logic: Modified UpdateProviderProfile in the accounts package to:

    • Accept CurrenciesAvailability in the payload (e.g., {"USD": false}).
    • Create or update ProviderCurrencyAvailability records based on the payload.
    • Update the Redis queue via UpdateRedisQueue func to reflect availability changes.
  3. Redis Queue Management: Added UpdateRedisQueue in the utils package to add/remove providers from Redis queues (key format:
    bucket_) based on is_available.

References

Closes #436

Testing

Describe how this can be tested by reviewers. Be specific about anything not tested and reasons why. If this project has unit and/or integration testing, tests should be added for new functionality and existing tests should complete without errors.

Please include any manual steps for testing end-to-end or functionality not covered by unit/integration tests.

Also include details of the environment this PR was developed in (language/platform/browser version).

  • This change adds test coverage for new/changed/fixed functionality

Checklist

  • I have added documentation and tests for new/changed functionality in this PR
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not main

By submitting a PR, I agree to Paycrest's Contributor Code of Conduct and Contribution Guide.

@sundayonah sundayonah requested review from chibie and 5ran6 as code owners March 24, 2025 21:31
types/types.go Outdated
MobileNumber string `json:"mobileNumber"`
DateOfBirth time.Time `json:"dateOfBirth"`
BusinessName string `json:"businessName"`
CurrenciesAvailability map[string]bool `json:"currencies_availability,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

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

a new field isn't necessary.

the currency being updated could be fetched from payload.Tokens[0].Currency, given only one currency can be updated per time

utils/utils.go Outdated
Comment on lines 582 to 609
// UpdateRedisQueue updates the Redis queue for a provider's availability for a specific currency.
func UpdateRedisQueue(ctx context.Context, redisClient *redis.Client, provider *ent.ProviderProfile, currency string, isAvailable bool) error {
// Fetch relevant buckets for the provider
buckets, err := storage.Client.ProvisionBucket.
Query().
Where(provisionbucket.HasProviderProfilesWith(providerprofile.IDEQ(provider.ID))).
All(ctx)
if err != nil {
return fmt.Errorf("failed to query buckets: %v", err)
}

for _, bucket := range buckets {
redisKey := fmt.Sprintf("bucket_%s_%s_%s", currency, bucket.MinAmount, bucket.MaxAmount)
if !isAvailable {
err := redisClient.SRem(ctx, redisKey, provider.ID).Err()
if err != nil {
return fmt.Errorf("failed to remove provider %s from Redis queue %s: %w", provider.ID, redisKey, err)
}
} else {
err := redisClient.SAdd(ctx, redisKey, provider.ID).Err()
if err != nil {
// Fixed a typo in the original error message ("Redisqueen" -> "Redis queue")
return fmt.Errorf("failed to add provider %s to Redis queue %s: %w", provider.ID, redisKey, err)
}
}
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

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

was this tested?

seems only the "DELETED_PROVIDER" approach works... this same util here should be used --> https://github.com/paycrest/aggregator/pull/443/files#diff-0df82f8689d3e8d881be0653ab4e9f8221c5835ec95a14930d11669e9c7f07ef

Comment on lines 312 to 362
// Handle currency-specific availability
if len(payload.CurrenciesAvailability) > 0 {
for currencyCode, isAvailable := range payload.CurrenciesAvailability {
currency, err := storage.Client.FiatCurrency.Query().
Where(fiatcurrency.CodeEQ(currencyCode)).
Only(ctx)
if err != nil {
u.APIResponse(ctx, http.StatusBadRequest, "error",
fmt.Sprintf("Currency not found: %s", currencyCode), nil)
return
}

existingAvailability, err := storage.Client.ProviderCurrencyAvailability.
Query().
Where(
providercurrencyavailability.HasProviderWith(providerprofile.IDEQ(provider.ID)),
providercurrencyavailability.HasCurrencyWith(fiatcurrency.IDEQ(currency.ID)),
).
Only(ctx)

if ent.IsNotFound(err) {
// Create new availability entry
_, err := storage.Client.ProviderCurrencyAvailability.
Create().
SetProvider(provider).
SetCurrency(currency).
SetIsAvailable(isAvailable).
Save(ctx)
if err != nil {
logger.Errorf("Failed to create availability record: %v", err)
continue
}
} else {
// Update existing record
_, err = existingAvailability.Update().
SetIsAvailable(isAvailable).
Save(ctx)
if err != nil {
logger.Errorf("Failed to update availability for provider %s, currency %s: %v", provider.ID, currencyCode, err)
continue
}
}

// Update Redis queue
err = utils.UpdateRedisQueue(ctx, storage.RedisClient, provider, currency.Code, isAvailable)
if err != nil {
logger.Errorf("Failed to update Redis queue for provider %s, currency %s: %v", provider.ID, currencyCode, err)
}
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

fix this given removal of CurrenciesAvailability in another comment

@@ -75,6 +75,7 @@ func (ProviderProfile) Edges() []ent.Edge {
Unique(),
edge.To("assigned_orders", LockPaymentOrder.Type).
Annotations(entsql.OnDelete(entsql.Cascade)),
edge.To("currency_availability", ProviderCurrencyAvailability.Type),
Copy link
Contributor

Choose a reason for hiding this comment

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

add ondelete cascade

@@ -46,5 +46,6 @@ func (FiatCurrency) Edges() []ent.Edge {
edge.To("institutions", Institution.Type),
edge.To("provider_order_tokens", ProviderOrderToken.Type).
Annotations(entsql.OnDelete(entsql.Cascade)),
edge.To("provider_availability", ProviderCurrencyAvailability.Type),
Copy link
Contributor

Choose a reason for hiding this comment

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

add ondelete cascade

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Switch off node for a specific currency
2 participants