73 lines
2.0 KiB
Go
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))
|
|
}
|