Fixes + stable gateway ids
This commit is contained in:
144
api/payments/storage/model/gateway_affinity.go
Normal file
144
api/payments/storage/model/gateway_affinity.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package model
|
||||
|
||||
import "strings"
|
||||
|
||||
// SelectGatewayByPreference picks a gateway candidate using persisted affinity hints.
|
||||
// Matching order:
|
||||
// 1) gateway ID + instance ID
|
||||
// 2) invoke URI
|
||||
// 3) gateway ID
|
||||
// 4) instance ID
|
||||
// 5) first candidate fallback
|
||||
func SelectGatewayByPreference(
|
||||
candidates []*GatewayInstanceDescriptor,
|
||||
gatewayID string,
|
||||
instanceID string,
|
||||
invokeURI string,
|
||||
) (*GatewayInstanceDescriptor, string) {
|
||||
if len(candidates) == 0 {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
gatewayID = strings.TrimSpace(gatewayID)
|
||||
instanceID = strings.TrimSpace(instanceID)
|
||||
invokeURI = strings.TrimSpace(invokeURI)
|
||||
|
||||
if gatewayID != "" && instanceID != "" {
|
||||
for _, entry := range candidates {
|
||||
if entry == nil {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(entry.ID), gatewayID) &&
|
||||
strings.EqualFold(strings.TrimSpace(entry.InstanceID), instanceID) {
|
||||
return entry, "exact"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if invokeURI != "" {
|
||||
for _, entry := range candidates {
|
||||
if entry == nil {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(entry.InvokeURI), invokeURI) {
|
||||
return entry, "invoke_uri"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if gatewayID != "" {
|
||||
for _, entry := range candidates {
|
||||
if entry == nil {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(entry.ID), gatewayID) {
|
||||
return entry, "gateway_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if instanceID != "" {
|
||||
for _, entry := range candidates {
|
||||
if entry == nil {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(entry.InstanceID), instanceID) {
|
||||
return entry, "instance_id"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, entry := range candidates {
|
||||
if entry != nil {
|
||||
return entry, "rail_fallback"
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
// GatewayDescriptorIdentityKey returns a stable dedupe key for gateway entries.
|
||||
// The key is composed from logical gateway ID + instance identity; invoke URI is
|
||||
// used as a fallback identity when instance ID is missing.
|
||||
func GatewayDescriptorIdentityKey(entry *GatewayInstanceDescriptor) string {
|
||||
if entry == nil {
|
||||
return ""
|
||||
}
|
||||
return GatewayIdentityKey(entry.ID, entry.InstanceID, entry.InvokeURI)
|
||||
}
|
||||
|
||||
// GatewayIdentityKey composes a stable identity key from gateway affinity fields.
|
||||
func GatewayIdentityKey(gatewayID string, instanceID string, invokeURI string) string {
|
||||
id := strings.ToLower(strings.TrimSpace(gatewayID))
|
||||
if id == "" {
|
||||
return ""
|
||||
}
|
||||
instance := strings.ToLower(strings.TrimSpace(instanceID))
|
||||
if instance == "" {
|
||||
instance = strings.ToLower(strings.TrimSpace(invokeURI))
|
||||
}
|
||||
if instance == "" {
|
||||
return id
|
||||
}
|
||||
return id + "|" + instance
|
||||
}
|
||||
|
||||
// LessGatewayDescriptor orders gateway descriptors deterministically.
|
||||
func LessGatewayDescriptor(left *GatewayInstanceDescriptor, right *GatewayInstanceDescriptor) bool {
|
||||
if left == nil {
|
||||
return right != nil
|
||||
}
|
||||
if right == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if cmp := compareFolded(left.ID, right.ID); cmp != 0 {
|
||||
return cmp < 0
|
||||
}
|
||||
if cmp := compareFolded(left.InstanceID, right.InstanceID); cmp != 0 {
|
||||
return cmp < 0
|
||||
}
|
||||
if cmp := compareFolded(left.InvokeURI, right.InvokeURI); cmp != 0 {
|
||||
return cmp < 0
|
||||
}
|
||||
if cmp := compareFolded(string(left.Rail), string(right.Rail)); cmp != 0 {
|
||||
return cmp < 0
|
||||
}
|
||||
if cmp := compareFolded(left.Network, right.Network); cmp != 0 {
|
||||
return cmp < 0
|
||||
}
|
||||
return compareFolded(left.Version, right.Version) < 0
|
||||
}
|
||||
|
||||
func compareFolded(left string, right string) int {
|
||||
l := strings.ToLower(strings.TrimSpace(left))
|
||||
r := strings.ToLower(strings.TrimSpace(right))
|
||||
switch {
|
||||
case l < r:
|
||||
return -1
|
||||
case l > r:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user