feat: refresh accounts automatically every five minutes
This commit is contained in:
+1
-1
@@ -80,7 +80,7 @@
|
||||
{timezone,theme,syncMinutes,retentionDays,beforeMinutes,notifyBefore,notifyAfter}
|
||||
```
|
||||
|
||||
任意非 `GET` 方法都按更新处理,前端使用 `PUT`;请求接受完整对象。`syncMinutes` 为 1–60,`retentionDays` 为 30–365,`beforeMinutes` 为 1–1440,时区必须能由 Go 加载;非法值返回 400。成功返回保存后的对象。
|
||||
任意非 `GET` 方法都按更新处理,前端使用 `PUT`;请求接受完整对象。`syncMinutes` 为兼容旧客户端保留的字段,服务端始终按 5 分钟自动同步并返回 `5`;`retentionDays` 为 30–365,`beforeMinutes` 为 1–1440,时区必须能由 Go 加载;非法值返回 400。成功返回保存后的对象。
|
||||
|
||||
### SMTP
|
||||
|
||||
|
||||
@@ -408,9 +408,9 @@ func (a *App) logout(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *App) general() GeneralSettings {
|
||||
g := defaults()
|
||||
a.store.GetJSON("general", &g)
|
||||
if g.SyncMinutes < 1 {
|
||||
g.SyncMinutes = 5
|
||||
}
|
||||
// Keep the legacy field in the response for old clients, but automatic
|
||||
// account synchronization is intentionally fixed at five minutes.
|
||||
g.SyncMinutes = automaticSyncMinutes
|
||||
if g.RetentionDays < 1 {
|
||||
g.RetentionDays = 90
|
||||
}
|
||||
@@ -430,6 +430,7 @@ func (a *App) generalAPI(w http.ResponseWriter, r *http.Request) {
|
||||
jsonOut(w, 400, map[string]string{"error": "无效时区"})
|
||||
return
|
||||
}
|
||||
g.SyncMinutes = automaticSyncMinutes
|
||||
_ = a.store.SetJSON("general", g)
|
||||
jsonOut(w, 200, g)
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ type accountRuntime struct {
|
||||
stopped bool
|
||||
}
|
||||
|
||||
const automaticSyncInterval = time.Duration(automaticSyncMinutes) * time.Minute
|
||||
|
||||
type codexClient interface {
|
||||
Start(context.Context) error
|
||||
Initialize(context.Context) error
|
||||
@@ -267,17 +269,18 @@ func (a *App) syncAll(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
func (a *App) scheduler() {
|
||||
t := time.NewTicker(time.Minute)
|
||||
defer t.Stop()
|
||||
maintenanceTicker := time.NewTicker(time.Minute)
|
||||
syncTicker := time.NewTicker(automaticSyncInterval)
|
||||
defer maintenanceTicker.Stop()
|
||||
defer syncTicker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-a.ctx.Done():
|
||||
return
|
||||
case <-t.C:
|
||||
case <-syncTicker.C:
|
||||
a.syncAll(context.Background())
|
||||
case <-maintenanceTicker.C:
|
||||
g := a.general()
|
||||
if time.Now().Unix()%(int64(g.SyncMinutes)*60) < 60 {
|
||||
a.syncAll(context.Background())
|
||||
}
|
||||
_, _ = a.store.Cleanup(g.RetentionDays)
|
||||
go a.processReminders()
|
||||
}
|
||||
|
||||
@@ -349,6 +349,19 @@ func TestPeakDailyTokensUsesOnlyTheCurrentTokenCycle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutomaticSyncIntervalIsFixedAtFiveMinutes(t *testing.T) {
|
||||
a := newReminderTestApp(t)
|
||||
if err := a.store.SetJSON("general", GeneralSettings{SyncMinutes: 60, RetentionDays: 90, BeforeMinutes: 30}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := a.general().SyncMinutes; got != automaticSyncMinutes {
|
||||
t.Fatalf("sync minutes = %d; want %d", got, automaticSyncMinutes)
|
||||
}
|
||||
if automaticSyncInterval != 5*time.Minute {
|
||||
t.Fatalf("automatic sync interval = %s; want 5m", automaticSyncInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlattenLimitReadsAppServerWindowDuration(t *testing.T) {
|
||||
var limit rawLimit
|
||||
if err := json.Unmarshal([]byte(`{
|
||||
|
||||
@@ -9,6 +9,9 @@ type GeneralSettings struct {
|
||||
NotifyBefore bool `json:"notifyBefore"`
|
||||
NotifyAfter bool `json:"notifyAfter"`
|
||||
}
|
||||
|
||||
const automaticSyncMinutes = 5
|
||||
|
||||
type SMTPSettings struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
@@ -92,5 +95,5 @@ type Dashboard struct {
|
||||
}
|
||||
|
||||
func defaults() GeneralSettings {
|
||||
return GeneralSettings{Timezone: "UTC", Theme: "system", SyncMinutes: 5, RetentionDays: 90, BeforeMinutes: 30, NotifyBefore: true, NotifyAfter: true}
|
||||
return GeneralSettings{Timezone: "UTC", Theme: "system", SyncMinutes: automaticSyncMinutes, RetentionDays: 90, BeforeMinutes: 30, NotifyBefore: true, NotifyAfter: true}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user