mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 09:40:12 +00:00
fix(server-transfer): break loader sort ties by transferID
NewServerTransferClass merged Verified and acked-rollback rows and sorted them by AckedAt only. On Windows time.Now() granularity is ~15.6ms, so MarkVerified and an immediately-following MarkRevertDelivered routinely share a timestamp. The stable sort then left the Verified candidate ahead of the rollback that is actually on disk and the agent was locked out on the next restart. Add transferID as a deterministic tiebreaker so the later rotation always wins.
This commit is contained in:
@@ -307,6 +307,7 @@ func NewServerTransferClass() *ServerTransferClass {
|
|||||||
|
|
||||||
type credCandidate struct {
|
type credCandidate struct {
|
||||||
serverID uint64
|
serverID uint64
|
||||||
|
transferID uint64
|
||||||
secret string
|
secret string
|
||||||
ackedAt time.Time
|
ackedAt time.Time
|
||||||
isRevert bool
|
isRevert bool
|
||||||
@@ -320,6 +321,7 @@ func NewServerTransferClass() *ServerTransferClass {
|
|||||||
}
|
}
|
||||||
candidates = append(candidates, credCandidate{
|
candidates = append(candidates, credCandidate{
|
||||||
serverID: t.ServerID,
|
serverID: t.ServerID,
|
||||||
|
transferID: t.ID,
|
||||||
secret: t.HandshakeSecret,
|
secret: t.HandshakeSecret,
|
||||||
ackedAt: *t.AckedAt,
|
ackedAt: *t.AckedAt,
|
||||||
toUserID: t.ToUserID,
|
toUserID: t.ToUserID,
|
||||||
@@ -332,13 +334,25 @@ func NewServerTransferClass() *ServerTransferClass {
|
|||||||
}
|
}
|
||||||
candidates = append(candidates, credCandidate{
|
candidates = append(candidates, credCandidate{
|
||||||
serverID: t.ServerID,
|
serverID: t.ServerID,
|
||||||
|
transferID: t.ID,
|
||||||
secret: t.RevertHandshakeSecret,
|
secret: t.RevertHandshakeSecret,
|
||||||
ackedAt: *t.AckedAt,
|
ackedAt: *t.AckedAt,
|
||||||
isRevert: true,
|
isRevert: true,
|
||||||
toUserID: t.FromUserID,
|
toUserID: t.FromUserID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// Sort newest-first by AckedAt, breaking ties with transferID. AckedAt
|
||||||
|
// alone is not enough on platforms whose time.Now() granularity is
|
||||||
|
// coarse (Windows: ~15.6ms): MarkVerified and the immediately-following
|
||||||
|
// MarkRevertDelivered routinely produce identical timestamps, and a
|
||||||
|
// stable sort then leaves the Verified candidate (appended first) ahead
|
||||||
|
// of the rollback that is actually on disk, locking the agent out on
|
||||||
|
// restart. transferID is monotonically increasing within a server's
|
||||||
|
// transfer lifecycle, so the later rotation always wins the tiebreak.
|
||||||
sort.SliceStable(candidates, func(i, j int) bool {
|
sort.SliceStable(candidates, func(i, j int) bool {
|
||||||
|
if candidates[i].ackedAt.Equal(candidates[j].ackedAt) {
|
||||||
|
return candidates[i].transferID > candidates[j].transferID
|
||||||
|
}
|
||||||
return candidates[i].ackedAt.After(candidates[j].ackedAt)
|
return candidates[i].ackedAt.After(candidates[j].ackedAt)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user