61 lines
2.2 KiB
Go
61 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"git.ipao.vip/rogee/go-sip/internal/dispatcher"
|
|
)
|
|
|
|
// maintainAgentSession renews before the ten-minute Agent session expires.
|
|
// A failed or invalid renewal stops admission rather than using the old lease.
|
|
func maintainAgentSession(ctx context.Context, active dispatcher.AgentSession, before time.Duration, renew func(context.Context, dispatcher.AgentSession) (dispatcher.AgentSession, error)) error {
|
|
if ctx == nil || renew == nil || before <= 0 {
|
|
return errors.New("Agent session renewal requires a context, interval and renewal operation")
|
|
}
|
|
for {
|
|
if ctx.Err() != nil {
|
|
return nil
|
|
}
|
|
if active.ExpiresAtUnixMs <= time.Now().UnixMilli() {
|
|
return fmt.Errorf("Agent %s session generation %d expired before renewal", active.AgentID, active.SessionGeneration)
|
|
}
|
|
wait := time.Until(time.UnixMilli(active.ExpiresAtUnixMs).Add(-before))
|
|
if wait < 0 {
|
|
wait = 0
|
|
}
|
|
timer := time.NewTimer(wait)
|
|
select {
|
|
case <-ctx.Done():
|
|
timer.Stop()
|
|
return nil
|
|
case <-timer.C:
|
|
}
|
|
if ctx.Err() != nil {
|
|
return nil
|
|
}
|
|
if active.ExpiresAtUnixMs <= time.Now().UnixMilli() {
|
|
return fmt.Errorf("Agent %s session generation %d expired before renewal", active.AgentID, active.SessionGeneration)
|
|
}
|
|
requestCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
next, err := renew(requestCtx, active)
|
|
cancel()
|
|
if err != nil {
|
|
if ctx.Err() != nil {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("renew Agent %s session generation %d: %w", active.AgentID, active.SessionGeneration, err)
|
|
}
|
|
if next.AgentID != active.AgentID || next.CellID != active.CellID || next.BootID != active.BootID ||
|
|
next.DispatcherEpoch != active.DispatcherEpoch || next.SessionGeneration <= active.SessionGeneration ||
|
|
next.ExpiresAtUnixMs <= active.ExpiresAtUnixMs || next.ExpiresAtUnixMs <= time.Now().Add(before).UnixMilli() {
|
|
return fmt.Errorf("Agent %s session generation %d renewal returned no usable session", active.AgentID, active.SessionGeneration)
|
|
}
|
|
slog.Info("Agent session renewed", "agent_id", next.AgentID, "session_generation", next.SessionGeneration, "expires_at_unix_ms", next.ExpiresAtUnixMs)
|
|
active = next
|
|
}
|
|
}
|