Files
goauto/server/app/goauto/device/current_task.go
T

73 lines
2.0 KiB
Go

package device
import (
"fmt"
"go-admin/app/goauto/models"
"gorm.io/gorm"
)
type deviceTaskRow struct {
ID uint64
DeviceID uint64
}
// currentTaskIDsForDevices derives the single task currently executing on each
// device across collection and purchase domains. A cross-domain conflict is a
// broken server invariant and must never be hidden by choosing either task.
func currentTaskIDsForDevices(db *gorm.DB, deviceIDs []uint64) (map[uint64]uint64, error) {
current := make(map[uint64]uint64)
if len(deviceIDs) == 0 {
return current, nil
}
var collectionTasks []deviceTaskRow
if err := db.Model(&models.CollectionTask{}).
Select("id, device_id").
Where("device_id IN ? AND status = ?", deviceIDs, models.TaskStatusRunning).
Scan(&collectionTasks).Error; err != nil {
return nil, internalError(err)
}
for _, task := range collectionTasks {
if _, exists := current[task.DeviceID]; exists {
return nil, deviceTaskConflictError(task.DeviceID)
}
current[task.DeviceID] = task.ID
}
var purchaseTasks []deviceTaskRow
if err := db.Model(&models.PurchaseTask{}).
Select("id, device_id").
Where("device_id IN ? AND status IN ?", deviceIDs, []string{
models.PurchaseTaskStatusRunning,
models.PurchaseTaskStatusOrderSubmitStarted,
}).
Scan(&purchaseTasks).Error; err != nil {
return nil, internalError(err)
}
for _, task := range purchaseTasks {
if _, exists := current[task.DeviceID]; exists {
return nil, deviceTaskConflictError(task.DeviceID)
}
current[task.DeviceID] = task.ID
}
return current, nil
}
func currentTaskForDevice(db *gorm.DB, deviceID uint64) (*uint64, error) {
current, err := currentTaskIDsForDevices(db, []uint64{deviceID})
if err != nil {
return nil, err
}
taskID, exists := current[deviceID]
if !exists {
return nil, nil
}
return &taskID, nil
}
func deviceTaskConflictError(deviceID uint64) error {
return internalError(fmt.Errorf("device %d has multiple running tasks across task domains", deviceID))
}