feat: sync deployed v1.0.0-rc.38-custom.42
Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
1 parent
aa6c3f50f4
commit
ceddfd3d6b
828 files changed
+122253
-13702
No files matched your search
@@ -0,0 +1,61 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// DetectionSchedule survives task-history cleanup and is never projected directly
|
||||
// to public APIs. Only automatic results advance this channel/kind clock.
|
||||
type DetectionSchedule struct {
|
||||
ChannelID int `gorm:"primaryKey;autoIncrement:false"`
|
||||
Kind string `gorm:"primaryKey;type:varchar(24)"`
|
||||
LastValid string `gorm:"type:varchar(16)"`
|
||||
IntervalMinutes int
|
||||
NextDueAt int64
|
||||
LastFinishedAt int64
|
||||
LastResultID string `gorm:"type:varchar(64)"`
|
||||
}
|
||||
|
||||
func NextDetectionInterval(lastValid, outcome string, current int) int {
|
||||
if outcome != "normal" && outcome != "degraded" {
|
||||
return 15
|
||||
}
|
||||
if lastValid == "" {
|
||||
return 30
|
||||
}
|
||||
if lastValid != outcome {
|
||||
return 15
|
||||
}
|
||||
if current == 15 {
|
||||
return 30
|
||||
}
|
||||
return 60
|
||||
}
|
||||
|
||||
func EnsureDetectionSchedule(ctx context.Context, seed DetectionSchedule) error {
|
||||
return DB.WithContext(ctx).Clauses(clause.OnConflict{DoNothing: true}).Create(&seed).Error
|
||||
}
|
||||
|
||||
func ApplyDetectionScheduleResult(ctx context.Context, channelID int, kind, resultID string, finishedAt int64, outcome string) error {
|
||||
return DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var state DetectionSchedule
|
||||
if err := lockForUpdate(tx).Where("channel_id = ? AND kind = ?", channelID, kind).First(&state).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
// A result is committed before its clock advances. Reconciliation can
|
||||
// safely replay it after a crash, without advancing the clock twice.
|
||||
if finishedAt <= state.LastFinishedAt || resultID == state.LastResultID {
|
||||
return nil
|
||||
}
|
||||
state.IntervalMinutes = NextDetectionInterval(state.LastValid, outcome, state.IntervalMinutes)
|
||||
if outcome == "normal" || outcome == "degraded" {
|
||||
state.LastValid = outcome
|
||||
}
|
||||
state.LastFinishedAt, state.LastResultID = finishedAt, resultID
|
||||
state.NextDueAt = finishedAt + int64(state.IntervalMinutes)*60
|
||||
return tx.Save(&state).Error
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user