-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
bring back last_seen in database #2579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Pull Request Revisions
✅ AI review completed for r6 HelpReact with emojis to give feedback on AI-generated reviews:
We'd love to hear from you—reach out anytime at [email protected]. |
c2570ad to
629e71a
Compare
629e71a to
11a7f5d
Compare
| Migrate: func(tx *gorm.DB) error { | ||
| _ = tx.Migrator().AddColumn(&types.Node{}, "last_seen") | ||
|
|
||
| return nil | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the migration function in hscontrol/db/db.go, you're ignoring the error from tx.Migrator().AddColumn(). This could potentially hide migration failures. Consider either properly handling the error or at least adding a comment explaining why it's safe to ignore.
| // SetLastSeen sets a node's last seen field indicating that we | ||
| // have recently communicating with this node. | ||
| func (hsdb *HSDatabase) SetLastSeen(nodeID types.NodeID, lastSeen time.Time) error { | ||
| return hsdb.Write(func(tx *gorm.DB) error { | ||
| return SetLastSeen(tx, nodeID, lastSeen) | ||
| }) | ||
| } | ||
|
|
||
| // SetLastSeen sets a node's last seen field indicating that we | ||
| // have recently communicating with this node. | ||
| func SetLastSeen(tx *gorm.DB, nodeID types.NodeID, lastSeen time.Time) error { | ||
| return tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("last_seen", lastSeen).Error | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/db/node.go, you have duplicated documentation comments for the SetLastSeen function. Consider removing the redundancy to maintain cleaner code.
hscontrol/grpcv1.go
Outdated
| resp.Online = true | ||
| resp.LastSeen = timestamppb.New(time.Now()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/grpcv1.go, you're setting LastSeen to the current time for online nodes, which differs from the pattern in hscontrol/mapper/tail.go where a similar operation is done. Consider extracting this logic into a shared utility function to ensure consistent behavior across the codebase.
| if node.LastSeen != nil { | ||
| h.db.SetLastSeen(node.ID, *node.LastSeen) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/poll.go, you're updating the LastSeen field in the database only if it's not nil. However, there's no clear validation ensuring that LastSeen gets initialized properly. Consider adding more robust handling for the case when LastSeen is unexpectedly nil.
hscontrol/mapper/mapper.go
Outdated
| for _, peer := range peers { | ||
| online := m.notif.IsLikelyConnected(peer.ID) | ||
| peer.IsOnline = &online | ||
| peer.IsOnline = online |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/mapper/mapper.go, you're changing from a pointer bool to a direct bool for IsOnline, which is a good simplification, but this could potentially cause issues if any other parts of the code expect IsOnline to be nullable. Have you verified compatibility across all usage sites?
hscontrol/mapper/tail.go
Outdated
| if node.IsOnline { | ||
| // If the node is online, return the current time. | ||
| tNode.LastSeen = ptr.To(time.Now()) | ||
| } else { | ||
| // LastSeen is only set when node is | ||
| // not connected to the control server. | ||
| tNode.LastSeen = node.LastSeen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/mapper/tail.go, the conditional logic for setting LastSeen has been updated but there could be a potential issue with consistency. While online nodes get the current time, offline nodes use the stored LastSeen which might be nil. Consider handling the nil case explicitly to avoid potential nil pointer dereferences later.
| // if the server is not running with HTTPS, we have to wait a bit before | ||
| // reconnection as the newest Tailscale client has a measure that will only | ||
| // reconnect over HTTPS if they saw a noise connection previously. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In integration/auth_key_test.go, removing the time.Sleep(time.Minute) might introduce flakiness in tests if the test relies on certain timing behaviors. Have you verified that the tests remain stable without this delay?
11a7f5d to
3ff0d58
Compare
|
|
||
| // LastSeen is when the node was last in contact with | ||
| // headscale. It is best effort and not persisted. | ||
| LastSeen *time.Time `gorm:"-"` | ||
|
|
||
| // DEPRECATED: Use the ApprovedRoutes field instead. | ||
| // TODO(kradalby): remove when ApprovedRoutes is used all over the code. | ||
| // Routes []Route `gorm:"constraint:OnDelete:CASCADE;"` | ||
| LastSeen *time.Time `gorm:"column:last_seen"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/types/node.go, the LastSeen field is now persisted to the database which is good, but consider adding validation in relevant functions to handle potential database errors when LastSeen is NULL in the database (for newly created nodes or after migrations).
hscontrol/mapper/tail.go
Outdated
| } else { | ||
| // LastSeen is only set when node is | ||
| // not connected to the control server. | ||
| tNode.LastSeen = node.LastSeen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/mapper/tail.go, consider adding a guard clause or default value when handling LastSeen for offline nodes: tNode.LastSeen = node.LastSeen. If node.LastSeen is nil, this could lead to unexpected behavior in downstream code that expects a valid time value.
| // Add back last_seen column to node table. | ||
| { | ||
| ID: "202505091439", | ||
| Migrate: func(tx *gorm.DB) error { | ||
| _ = tx.Migrator().AddColumn(&types.Node{}, "last_seen") | ||
|
|
||
| return nil | ||
| }, | ||
| Rollback: func(db *gorm.DB) error { return nil }, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In hscontrol/db/db.go, you're adding a new migration but not validating whether the column already exists before attempting to add it. Consider adding a condition to check if the column exists to avoid potential errors when running the migration multiple times.
Fixes juanfont#2574 Signed-off-by: Kristoffer Dalby <[email protected]>
Signed-off-by: Kristoffer Dalby <[email protected]>
3ff0d58 to
4414dfc
Compare
| assertLastSeenSet(t, node) | ||
| } | ||
|
|
||
| allAddrs := lo.Map(allIps, func(x netip.Addr, index int) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In integration/auth_key_test.go, allIps is first fetched on line 48-49 but then used much later in the test on line 127. Between these points, clients log out and log back in, potentially changing the IP addresses. Consider either refreshing the IP list before use or using a more reliable identifier for nodes.
Fixes #2574