Add node neighbor link updater controller#9
Add node neighbor link updater controller#9MitchLewis930 wants to merge 1 commit intopr_049_beforefrom
Conversation
This controller is responsible for monitoring nodes that request a neighbor link update. It provides a single place in the application where all node neighbor link are updates are performed as insertNeighbor are sprinkled in the code base. Additionally given the central location we can provide additional module health signals should neighbor link updates failed. Signed-off-by: Fernand Galiana <fernand.galiana@gmail.com>
Greptile OverviewGreptile SummaryThis PR introduces a centralized queue-based controller for managing node neighbor link updates. The implementation replaces direct asynchronous Key Changes:
Critical Issues Found:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Daemon
participant NodeManager
participant Queue
participant Controller
participant NodeNeighbors
participant NetLink
Note over Daemon: Daemon startup
Daemon->>NodeManager: StartNodeNeighborLinkUpdater(nh)
NodeManager->>Controller: Create controller with RunInterval=10s
Note over NodeManager: Node update triggered
NodeManager->>NodeManager: nodeUpdate() or StartNeighborRefresh()
NodeManager->>Queue: Enqueue(node, refresh)
Queue-->>Queue: push(nodeQueueEntry)
Note over Controller: Every 10 seconds
Controller->>Queue: isEmpty()
alt Queue has items
loop Process all nodes
Controller->>Queue: pop()
Queue-->>Controller: nodeQueueEntry
Controller->>NodeNeighbors: NodeNeighborRefresh(ctx, node, refresh)
NodeNeighbors->>NetLink: insertNeighbor4/6()
NetLink-->>NodeNeighbors: result
alt Success
NodeNeighbors-->>Controller: nil
Controller->>Controller: Report health: OK
else Error
NodeNeighbors-->>Controller: error
Controller->>Controller: Report health: Degraded
end
end
else Queue empty
Controller-->>Controller: return nil
end
|
| func (m *manager) Enqueue(n *nodeTypes.Node, refresh bool) { | ||
| if n == nil { | ||
| log.WithFields(logrus.Fields{ | ||
| logfields.LogSubsys: "enqueue", | ||
| }).Warn("Skipping nodeNeighbor insert: No node given") | ||
| } | ||
| m.nodeNeighborQueue.push(&nodeQueueEntry{node: n, refresh: refresh}) |
There was a problem hiding this comment.
Missing return after warning - when n == nil, the function logs a warning but continues to enqueue a nil node, which will cause errors in the controller.
| func (m *manager) Enqueue(n *nodeTypes.Node, refresh bool) { | |
| if n == nil { | |
| log.WithFields(logrus.Fields{ | |
| logfields.LogSubsys: "enqueue", | |
| }).Warn("Skipping nodeNeighbor insert: No node given") | |
| } | |
| m.nodeNeighborQueue.push(&nodeQueueEntry{node: n, refresh: refresh}) | |
| func (m *manager) Enqueue(n *nodeTypes.Node, refresh bool) { | |
| if n == nil { | |
| log.WithFields(logrus.Fields{ | |
| logfields.LogSubsys: "enqueue", | |
| }).Warn("Skipping nodeNeighbor insert: No node given") | |
| return | |
| } | |
| m.nodeNeighborQueue.push(&nodeQueueEntry{node: n, refresh: refresh}) | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/node/manager/manager.go
Line: 143:149
Comment:
Missing `return` after warning - when `n == nil`, the function logs a warning but continues to enqueue a nil node, which will cause errors in the controller.
```suggestion
func (m *manager) Enqueue(n *nodeTypes.Node, refresh bool) {
if n == nil {
log.WithFields(logrus.Fields{
logfields.LogSubsys: "enqueue",
}).Warn("Skipping nodeNeighbor insert: No node given")
return
}
m.nodeNeighborQueue.push(&nodeQueueEntry{node: n, refresh: refresh})
}
```
How can I resolve this? If you propose a fix, please make it concise.| for { | ||
| e := m.nodeNeighborQueue.pop() | ||
| if e == nil || e.node == nil { | ||
| errs = errors.Join(errs, fmt.Errorf("invalid node spec found in queue: %#v", e)) | ||
| break | ||
| } |
There was a problem hiding this comment.
Controller processes only one item per interval - the loop breaks immediately when pop() returns nil, but this should drain all items in the queue. With defaultNodeUpdateInterval of 10 seconds, this will only process one node every 10 seconds, creating a backlog.
Change break to continue to skip invalid entries without stopping queue processing:
| for { | |
| e := m.nodeNeighborQueue.pop() | |
| if e == nil || e.node == nil { | |
| errs = errors.Join(errs, fmt.Errorf("invalid node spec found in queue: %#v", e)) | |
| break | |
| } | |
| for { | |
| e := m.nodeNeighborQueue.pop() | |
| if e == nil { | |
| break | |
| } | |
| if e.node == nil { | |
| errs = errors.Join(errs, fmt.Errorf("invalid node spec found in queue: %#v", e)) | |
| continue | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/node/manager/manager.go
Line: 875:880
Comment:
Controller processes only one item per interval - the loop breaks immediately when `pop()` returns `nil`, but this should drain all items in the queue. With `defaultNodeUpdateInterval` of 10 seconds, this will only process one node every 10 seconds, creating a backlog.
Change `break` to `continue` to skip invalid entries without stopping queue processing:
```suggestion
for {
e := m.nodeNeighborQueue.pop()
if e == nil {
break
}
if e.node == nil {
errs = errors.Join(errs, fmt.Errorf("invalid node spec found in queue: %#v", e))
continue
}
```
How can I resolve this? If you propose a fix, please make it concise.
Additional Comments (1)
Prompt To Fix With AIThis is a comment left during a code review.
Path: pkg/node/manager/queue.go
Line: 27:38
Comment:
Race condition: `isEmpty()` check at line 28 and lock acquisition at line 32 are not atomic. Between checking `isEmpty()` (which releases the read lock) and acquiring the write lock, another goroutine could pop the last item, causing a panic when accessing `q.items[0]` on an empty slice.
```suggestion
func (q *queue[T]) pop() *T {
q.mx.Lock()
defer q.mx.Unlock()
if len(q.items) == 0 {
return nil
}
t := q.items[0]
q.items = q.items[1:]
return t
}
```
How can I resolve this? If you propose a fix, please make it concise. |
PR_049