feat(leonardo): session keepalive 独立成 1 分钟循环,并记录续期/失败计数
maintenance 的一次 tick 可能跑几十分钟(光 adobe cookie profile 就 219 个),挂在里面会把 5 分钟的保活拉长成 tick 的实际耗时。
This commit is contained in:
@@ -63,6 +63,10 @@ func NewMaintenanceService(tokens *repo.TokenRepository, tokenSvc *TokenService,
|
|||||||
func (m *MaintenanceService) Run(ctx context.Context) {
|
func (m *MaintenanceService) Run(ctx context.Context) {
|
||||||
ticker := time.NewTicker(m.interval)
|
ticker := time.NewTicker(m.interval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
// The leonardo session keep-alive gets its own loop: one tick() can take tens
|
||||||
|
// of minutes (219 adobe cookie profiles alone), which would stretch a 5-minute
|
||||||
|
// keep-alive to the tick's real duration.
|
||||||
|
go m.runLeonardoKeepalive(ctx)
|
||||||
m.tick(ctx)
|
m.tick(ctx)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -74,6 +78,25 @@ func (m *MaintenanceService) Run(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runLeonardoKeepalive re-checks every minute which leonardo accounts are due for
|
||||||
|
// a session renewal (the 5-minute due-ness itself is read per account from the DB,
|
||||||
|
// so a restart can't skip one).
|
||||||
|
func (m *MaintenanceService) runLeonardoKeepalive(ctx context.Context) {
|
||||||
|
if m.tokenSvc == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ticker := time.NewTicker(time.Minute)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
m.tokenSvc.RefreshLeonardoSessions(ctx)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// syncRecoveredQuota re-probes each just-recovered account so its displayed
|
// syncRecoveredQuota re-probes each just-recovered account so its displayed
|
||||||
// balance reflects the post-reset value (these providers only sync quota when
|
// balance reflects the post-reset value (these providers only sync quota when
|
||||||
// accessed). krea additionally needs /app (Activate) to actually grant the daily
|
// accessed). krea additionally needs /app (Activate) to actually grant the daily
|
||||||
@@ -165,12 +188,6 @@ func (m *MaintenanceService) tick(ctx context.Context) {
|
|||||||
// means the membership lapsed → disable+dead; otherwise re-sync the
|
// means the membership lapsed → disable+dead; otherwise re-sync the
|
||||||
// credits balance and 恢复时间 (from the credits' weekly reset).
|
// credits balance and 恢复时间 (from the credits' weekly reset).
|
||||||
m.tokenSvc.RefreshGrokLiveness(ctx)
|
m.tokenSvc.RefreshGrokLiveness(ctx)
|
||||||
// 1f. Keep leonardo's better-auth session rolling: get-session extends the
|
|
||||||
// session and rotates the cookie, so re-minting stops a dormant
|
|
||||||
// account's cookie from lapsing (a lapsed one can only be fixed by
|
|
||||||
// re-importing a browser cookie). Due-ness is read per account from
|
|
||||||
// meta["session_kept_at"], so a restart can't skip a renewal.
|
|
||||||
m.tokenSvc.RefreshLeonardoSessions(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Auto-renew Adobe cookies whose refresh interval has elapsed.
|
// 2. Auto-renew Adobe cookies whose refresh interval has elapsed.
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ func (s *TokenService) RefreshLeonardoSessions(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
due := time.Now().Add(-leonardoKeepaliveEvery).Unix()
|
due := time.Now().Add(-leonardoKeepaliveEvery).Unix()
|
||||||
proxied := false
|
proxied := false
|
||||||
|
renewed, failed := 0, 0
|
||||||
for i := range items {
|
for i := range items {
|
||||||
a := items[i]
|
a := items[i]
|
||||||
if a.Dead || a.Status == "disabled" || strings.TrimSpace(a.Value) == "" {
|
if a.Dead || a.Status == "disabled" || strings.TrimSpace(a.Value) == "" {
|
||||||
@@ -188,6 +189,7 @@ func (s *TokenService) RefreshLeonardoSessions(ctx context.Context) {
|
|||||||
_, err := s.leonardo.ProbeSession(callCtx, a.Value)
|
_, err := s.leonardo.ProbeSession(callCtx, a.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
|
failed++
|
||||||
if errors.Is(err, leonardo.ErrAuth) {
|
if errors.Is(err, leonardo.ErrAuth) {
|
||||||
log.Printf("leonardo %s: session keepalive auth failure (%v)", a.ID, err)
|
log.Printf("leonardo %s: session keepalive auth failure (%v)", a.ID, err)
|
||||||
}
|
}
|
||||||
@@ -202,6 +204,10 @@ func (s *TokenService) RefreshLeonardoSessions(ctx context.Context) {
|
|||||||
fields["meta"] = meta
|
fields["meta"] = meta
|
||||||
_, _ = s.tokens.Update(callCtx, "leonardo", a.ID, fields)
|
_, _ = s.tokens.Update(callCtx, "leonardo", a.ID, fields)
|
||||||
cancel()
|
cancel()
|
||||||
|
renewed++
|
||||||
|
}
|
||||||
|
if renewed > 0 || failed > 0 {
|
||||||
|
log.Printf("leonardo: session keepalive renewed %d, failed %d", renewed, failed)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user