45 строки
2.1 KiB
Go
45 строки
2.1 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
const maintenanceStartNotificationPrefix = "maintenance:%d:start:"
|
|
|
|
// MaintenanceStartNotificationKey uniquely identifies one contact's warning
|
|
// for one schedule revision and occurrence. Updated windows get a new revision
|
|
// while concurrent scheduler replicas share the same key.
|
|
func MaintenanceStartNotificationKey(maintenanceID int64, revision, startsAt time.Time, timezone string, notificationID, contactID int64) string {
|
|
loc, err := time.LoadLocation(timezone)
|
|
if err != nil || timezone == "SAME_AS_SERVER" || timezone == "" {
|
|
loc = time.UTC
|
|
}
|
|
// A fall-back hour can have two UTC instants for one wall-clock occurrence.
|
|
// Warnings are once per civil occurrence, matching the recurrence editor.
|
|
civilOccurrence := startsAt.In(loc).Format("200601021504")
|
|
return fmt.Sprintf("maintenance:%d:start:%d:%s:notification:%d:contact:%d", maintenanceID, revision.UnixNano(), civilOccurrence, notificationID, contactID)
|
|
}
|
|
|
|
// CancelMaintenanceStartNotificationsTx prevents queued warnings from being
|
|
// delivered after an operator pauses, changes, or deletes the maintenance.
|
|
// Leased work may already be executing and cannot be recalled from a worker.
|
|
func CancelMaintenanceStartNotificationsTx(tx *gorm.DB, maintenanceID int64, reason string) error {
|
|
prefix := fmt.Sprintf(maintenanceStartNotificationPrefix, maintenanceID) + "%"
|
|
var tasks []Task
|
|
if err := tx.Clauses(SkipLockedClause).Where("idempotency_key LIKE ? AND state IN ?", prefix, []string{TaskStateQueued, TaskStateFailedRetry}).Find(&tasks).Error; err != nil {
|
|
return err
|
|
}
|
|
for i := range tasks {
|
|
if err := tx.Model(&Task{}).Where("id = ? AND state IN ?", tasks[i].ID, []string{TaskStateQueued, TaskStateFailedRetry}).Updates(map[string]any{"state": TaskStateDead, "last_error": "canceled: " + reason, "payload": []byte(`{}`), "lease_owner": "", "lease_token": "", "lease_expires_at": nil}).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := FinalizeNotificationTaskTx(tx, &tasks[i], "canceled", "canceled: "+reason); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|