fix(group): bound push pressure and synchronize load agents

This commit is contained in:
richjohnrambo
2026-10-04 00:49:27 +08:00
parent 746f75ab0f
commit 7b25365ec3
14 changed files with 476 additions and 47 deletions
+78 -12
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"
@@ -27,32 +28,39 @@ func (s testThirdPartyConfigStore) Get(_ string, keys ...string) (map[string]str
type testDevicePushTokenStore struct {
devices map[types.Uid][]types.DeviceDef
calls int
}
func (s *testDevicePushTokenStore) Upsert(types.TenantID, *types.DevicePushToken) (*types.DevicePushToken, error) {
return nil, nil
}
func (s *testDevicePushTokenStore) GetAllByProvider(types.TenantID, string, ...types.Uid) (map[types.Uid][]types.DeviceDef, int, error) {
func (s *testDevicePushTokenStore) GetAllByProvider(_ types.TenantID, _ string, uids ...types.Uid) (map[types.Uid][]types.DeviceDef, int, error) {
s.calls++
result := make(map[types.Uid][]types.DeviceDef, len(uids))
count := 0
for _, devices := range s.devices {
for _, uid := range uids {
devices := s.devices[uid]
result[uid] = devices
count += len(devices)
}
return s.devices, count, nil
return result, count, nil
}
func TestNormalizeConfigLoadsThirdPartyConfig(t *testing.T) {
oldConfig := store.ThirdPartyConfig
store.ThirdPartyConfig = testThirdPartyConfigStore{
"jpush_enabled": "1",
"jpush_app_key": "app-key",
"jpush_master_secret": "master",
"jpush_api_domain": "https://push.example.com/",
"jpush_push_path": "v3/push",
"jpush_default_ttl_seconds": "123",
"jpush_call_ttl_seconds": "45",
"jpush_use_alias": "false",
"jpush_classification": "1",
"jpush_enabled": "1",
"jpush_app_key": "app-key",
"jpush_master_secret": "master",
"jpush_api_domain": "https://push.example.com/",
"jpush_push_path": "v3/push",
"jpush_workers": "4",
"jpush_device_cache_ttl_seconds": "45",
"jpush_default_ttl_seconds": "123",
"jpush_call_ttl_seconds": "45",
"jpush_use_alias": "false",
"jpush_classification": "1",
}
defer func() { store.ThirdPartyConfig = oldConfig }()
@@ -68,6 +76,9 @@ func TestNormalizeConfigLoadsThirdPartyConfig(t *testing.T) {
if config.APIDomain != "https://push.example.com" || config.PushPath != "/v3/push" {
t.Fatalf("unexpected endpoint: %#v", config)
}
if config.Workers != 4 || config.DeviceCacheTTLSeconds != 45 {
t.Fatalf("unexpected worker/cache config: %#v", config)
}
if config.DefaultTTLSeconds != 123 || config.CallTTLSeconds != 45 || config.UseAlias == nil || *config.UseAlias {
t.Fatalf("unexpected ttl/use_alias: %#v", config)
}
@@ -119,6 +130,8 @@ func TestAliasForUidUsesJPushSafeCharacters(t *testing.T) {
}
func TestPreparePayloadsCanUseRegistrationID(t *testing.T) {
resetDeviceCache()
t.Cleanup(resetDeviceCache)
oldTokens := store.DevicePushTokens
uid := types.Uid(42)
store.DevicePushTokens = &testDevicePushTokenStore{devices: map[types.Uid][]types.DeviceDef{
@@ -147,6 +160,8 @@ func TestPreparePayloadsCanUseRegistrationID(t *testing.T) {
}
func TestPreparePayloadsDoesNotDropRecipientWithDeliveredSession(t *testing.T) {
resetDeviceCache()
t.Cleanup(resetDeviceCache)
oldTokens := store.DevicePushTokens
uid := types.Uid(42)
store.DevicePushTokens = &testDevicePushTokenStore{devices: map[types.Uid][]types.DeviceDef{
@@ -170,6 +185,57 @@ func TestPreparePayloadsDoesNotDropRecipientWithDeliveredSession(t *testing.T) {
}
}
func TestPreparePayloadsCachesEmptyDeviceLookups(t *testing.T) {
resetDeviceCache()
t.Cleanup(resetDeviceCache)
oldTokens := store.DevicePushTokens
tokens := &testDevicePushTokenStore{devices: map[types.Uid][]types.DeviceDef{}}
store.DevicePushTokens = tokens
t.Cleanup(func() { store.DevicePushTokens = oldTokens })
useAlias := false
config := &configType{Title: "MeetingIM", DefaultTTLSeconds: 86400, CallTTLSeconds: 60,
DeviceCacheTTLSeconds: 30, UseAlias: &useAlias}
receipt := &push.Receipt{
TenantID: 7,
To: map[types.Uid]push.Recipient{42: {}, 43: {}},
Payload: push.Payload{What: push.ActMsg, Topic: "grpTopic", SeqId: 9, Timestamp: time.Now()},
}
preparePayloads(receipt, config)
preparePayloads(receipt, config)
if tokens.calls != 1 {
t.Fatalf("device store calls=%d want=1", tokens.calls)
}
}
func TestPreparePayloadsCoalescesConcurrentDeviceLookups(t *testing.T) {
resetDeviceCache()
t.Cleanup(resetDeviceCache)
oldTokens := store.DevicePushTokens
tokens := &testDevicePushTokenStore{devices: map[types.Uid][]types.DeviceDef{}}
store.DevicePushTokens = tokens
t.Cleanup(func() { store.DevicePushTokens = oldTokens })
useAlias := false
config := &configType{Title: "MeetingIM", DefaultTTLSeconds: 86400, CallTTLSeconds: 60,
DeviceCacheTTLSeconds: 30, UseAlias: &useAlias}
receipt := &push.Receipt{
TenantID: 7,
To: map[types.Uid]push.Recipient{42: {}, 43: {}},
Payload: push.Payload{What: push.ActMsg, Topic: "grpTopic", SeqId: 9, Timestamp: time.Now()},
}
var wg sync.WaitGroup
for range 20 {
wg.Add(1)
go func() {
defer wg.Done()
preparePayloads(receipt, config)
}()
}
wg.Wait()
if tokens.calls != 1 {
t.Fatalf("device store calls=%d want=1", tokens.calls)
}
}
func TestBuildPayloadUsesShortTTLForCalls(t *testing.T) {
expiresAt := time.Now().Add(30 * time.Second).UTC().Format(time.RFC3339Nano)
config := &configType{Title: "MeetingIM", DefaultTTLSeconds: 86400, CallTTLSeconds: 60}