Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
package perfmetrics
|
|
|
|
import (
|
|
"context"
|
|
"github.com/QuantumNous/new-api/common"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var liveSuccess sync.Map
|
|
|
|
type successTime struct {
|
|
sync.Mutex
|
|
at int64
|
|
}
|
|
|
|
func recordUserSuccess(group string, at int64) {
|
|
if group == "" {
|
|
return
|
|
}
|
|
value, _ := liveSuccess.LoadOrStore(group, &successTime{})
|
|
v := value.(*successTime)
|
|
v.Lock()
|
|
v.at = max(v.at, at)
|
|
v.Unlock()
|
|
if common.RedisEnabled && common.RDB != nil {
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
defer cancel()
|
|
// A delayed writer must not replace a newer successful request.
|
|
_ = common.RDB.Eval(ctx, `local old=tonumber(redis.call('GET',KEYS[1]) or '0'); if tonumber(ARGV[1])>old then redis.call('SET',KEYS[1],ARGV[1],'EX',900) end; return 1`, []string{"status:user-success:" + group}, at).Err()
|
|
}
|
|
}
|
|
|
|
func LatestUserSuccess(ctx context.Context, groups []string) map[string]int64 {
|
|
result := map[string]int64{}
|
|
for _, group := range groups {
|
|
if value, ok := liveSuccess.Load(group); ok {
|
|
v := value.(*successTime)
|
|
v.Lock()
|
|
result[group] = v.at
|
|
v.Unlock()
|
|
}
|
|
}
|
|
if common.RedisEnabled && common.RDB != nil && len(groups) > 0 {
|
|
keys := make([]string, len(groups))
|
|
for i, g := range groups {
|
|
keys[i] = "status:user-success:" + g
|
|
}
|
|
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
|
defer cancel()
|
|
values, err := common.RDB.MGet(ctx, keys...).Result()
|
|
if err == nil {
|
|
for i, value := range values {
|
|
if s, ok := value.(string); ok {
|
|
at, _ := strconv.ParseInt(s, 10, 64)
|
|
result[groups[i]] = max(result[groups[i]], at)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|