@@ -17,6 +17,7 @@ package agents
1717
1818import (
1919 "context"
20+ "fmt"
2021 "runtime/pprof"
2122 "strings"
2223 "time"
@@ -173,8 +174,10 @@ func (h *Handler) Run(stream agentv1.AgentService_ConnectServer) error {
173174
174175func (h * Handler ) stateChanged (ctx context.Context , req * agentv1.StateChangedRequest ) error {
175176 var PMMAgentID string
177+ var portsChanged bool
178+ l := logger .Get (ctx )
176179
177- errTX := h .db .InTransaction ( func (tx * reform.TX ) error {
180+ errTX := h .db .InTransactionContext ( ctx , nil , func (tx * reform.TX ) error {
178181 var agentIDs []string
179182 var err error
180183 req .AgentId = strings .TrimPrefix (req .AgentId , "/agent_id/" )
@@ -184,6 +187,13 @@ func (h *Handler) stateChanged(ctx context.Context, req *agentv1.StateChangedReq
184187 }
185188
186189 for _ , agentID := range agentIDs {
190+ // Check if port changed before updating
191+ if checkPortChanged (tx .Querier , agentID , req .ListenPort ) {
192+ portsChanged = true
193+ // TODO: change to debug after PMM-14267 is resolved, but for now we want to have clear logs about port changes
194+ l .Infof ("Port changed for agent %s, will trigger immediate VM config update" , agentID )
195+ }
196+
187197 err := updateAgentStatus (
188198 ctx ,
189199 tx .Querier ,
@@ -202,7 +212,18 @@ func (h *Handler) stateChanged(ctx context.Context, req *agentv1.StateChangedReq
202212 return errTX
203213 }
204214
205- h .vmdb .RequestConfigurationUpdate ()
215+ // For port changes, force immediate synchronous config update to prevent
216+ // VictoriaMetrics from scraping stale ports (PMM-14267)
217+ if portsChanged {
218+ l .Warn ("Listen port changed, forcing immediate VictoriaMetrics configuration update" )
219+ if err := h .vmdb .ForceConfigurationUpdate (ctx ); err != nil {
220+ return fmt .Errorf ("failed to force configuration update: %w" , err )
221+ }
222+ } else {
223+ // Normal async update
224+ h .vmdb .RequestConfigurationUpdate ()
225+ }
226+
206227 agent , err := models .FindAgentByID (h .db .Querier , PMMAgentID )
207228 if err != nil {
208229 return err
@@ -215,6 +236,19 @@ func (h *Handler) stateChanged(ctx context.Context, req *agentv1.StateChangedReq
215236 return nil
216237}
217238
239+ // checkPortChanged checks if the agent's listen port is changing.
240+ func checkPortChanged (q * reform.Querier , agentID string , newPort uint32 ) bool {
241+ agent , err := models .FindAgentByID (q , agentID )
242+ if err != nil {
243+ // Can't determine, assume no change
244+ return false
245+ }
246+ oldPort := pointer .GetUint16 (agent .ListenPort )
247+ newPort16 := uint16 (newPort ) //nolint:gosec
248+ // Port changed if old port exists and is different from new port
249+ return oldPort != 0 && oldPort != newPort16
250+ }
251+
218252func updateAgentStatus (
219253 ctx context.Context ,
220254 q * reform.Querier ,
@@ -227,8 +261,7 @@ func updateAgentStatus(
227261 l := logger .Get (ctx )
228262 l .Debugf ("updateAgentStatus: %s %s %d" , agentID , status , listenPort )
229263
230- agent := & models.Agent {AgentID : agentID }
231- err := q .Reload (agent )
264+ agent , err := models .FindAgentByID (q , agentID )
232265
233266 // agent can be already deleted, but we still can receive status message from pmm-agent.
234267 if errors .Is (err , reform .ErrNoRows ) {
0 commit comments