2026-04-06 15:48:37 +05:30
// Copyright IBM Corp. 2020, 2026
2025-01-09 10:26:37 -08:00
// SPDX-License-Identifier: BUSL-1.1
package worker
import (
"context"
"math/rand"
"time"
2026-10-12 10:33:41 -07:00
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/daemon/worker/session"
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/errors"
"repo.anhonesthost.net/CyberCoveLLC/threshold/internal/event"
pbs "repo.anhonesthost.net/CyberCoveLLC/threshold/internal/gen/controller/servers/services"
2025-01-09 10:26:37 -08:00
)
// lastStatistics holds the last successful statistics RPC time.
type lastStatistics struct {
LastSuccessfulRequestTime time . Time
}
func ( w * Worker ) startStatisticsTicking ( cancelCtx context . Context ) {
const op = "worker.(Worker).startStatisticsTicking"
r := rand . New ( rand . NewSource ( time . Now (). UnixNano ()))
timer := time . NewTimer ( 0 )
for {
select {
case <- cancelCtx . Done ():
event . WriteSysEvent ( w . baseContext , op , "statistics ticking shutting down" )
return
case <- timer . C :
err := w . sendStatistic ( cancelCtx )
if err != nil {
event . WriteError ( w . baseContext , op , err )
}
// Add a bit of jitter to the wait, so we aren't always getting,
// statistics updates at the exact same intervals, to ease the load on the DB.
timer . Reset ( w . statisticsInterval + getRandomInterval ( r ))
}
}
}
func ( w * Worker ) sendStatistic ( cancelCtx context . Context ) error {
const op = "worker.(Worker).sendStatistic"
// skip when the workerId is not available
if w . LastRoutingInfoSuccess () == nil {
return errors . New ( cancelCtx , errors . Internal , op , "missing latest status" )
}
workerId := w . LastRoutingInfoSuccess (). GetWorkerId ()
if workerId == "" {
return errors . New ( cancelCtx , errors . Internal , op , "worker id is empty" )
}
sessions := [] * pbs . SessionStatistics {}
w . sessionManager . ForEachLocalSession ( func ( s session . Session ) bool {
localConnections := s . GetLocalConnections ()
connections := make ([] * pbs . Connection , 0 , len ( localConnections ))
for connectionId , conn := range localConnections {
connections = append ( connections , & pbs . Connection {
ConnectionId : connectionId ,
BytesUp : conn . BytesUp (),
BytesDown : conn . BytesDown (),
Status : conn . Status ,
})
}
sessions = append ( sessions , & pbs . SessionStatistics {
SessionId : s . GetId (),
Connections : connections ,
})
return true
})
// skip when there are no sessions to report
if len ( sessions ) == 0 {
return nil
}
clientCon := w . GrpcClientConn . Load ()
client := pbs . NewServerCoordinationServiceClient ( clientCon )
statisticsCtx , statusCancel := context . WithTimeout ( cancelCtx , time . Duration ( w . statisticsCallTimeoutDuration . Load ()))
defer statusCancel ()
_ , err := client . Statistics ( statisticsCtx , & pbs . StatisticsRequest {
WorkerId : workerId ,
Sessions : sessions ,
})
if err != nil {
return errors . Wrap ( cancelCtx , err , op , errors . WithCode ( errors . Internal ), errors . WithMsg ( "error making statistics request to controller: controller_address: %s" , clientCon . Target ()))
}
w . lastStatisticsSuccess . Store ( & lastStatistics {
LastSuccessfulRequestTime : time . Now (),
})
return nil
}