Normalize task IDs and artifact folder prefixes
This commit is contained in:
@@ -33,8 +33,27 @@ var apiListNvidiaGPUs = func(a *app.App) ([]platform.NvidiaGPU, error) {
|
||||
|
||||
var jobCounter atomic.Uint64
|
||||
|
||||
func newJobID(prefix string) string {
|
||||
return fmt.Sprintf("%s-%d", prefix, jobCounter.Add(1))
|
||||
func newJobID(_ string) string {
|
||||
start := int((jobCounter.Add(1) - 1) % 1000)
|
||||
globalQueue.mu.Lock()
|
||||
defer globalQueue.mu.Unlock()
|
||||
for offset := 0; offset < 1000; offset++ {
|
||||
n := (start + offset) % 1000
|
||||
id := fmt.Sprintf("TASK-%03d", n)
|
||||
if !taskIDInUseLocked(id) {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("TASK-%03d", start)
|
||||
}
|
||||
|
||||
func taskIDInUseLocked(id string) bool {
|
||||
for _, t := range globalQueue.tasks {
|
||||
if t != nil && t.ID == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type taskRunResponse struct {
|
||||
|
||||
@@ -1149,7 +1149,32 @@ func taskArtifactsDir(root string, t *Task, status string) string {
|
||||
if strings.TrimSpace(root) == "" || t == nil {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(root, fmt.Sprintf("%s_%s_%s", t.ID, sanitizeTaskFolderPart(t.Name), taskFolderStatus(status)))
|
||||
prefix := taskFolderNumberPrefix(t.ID)
|
||||
return filepath.Join(root, fmt.Sprintf("%s_%s_%s", prefix, sanitizeTaskFolderPart(t.Name), taskFolderStatus(status)))
|
||||
}
|
||||
|
||||
func taskFolderNumberPrefix(taskID string) string {
|
||||
taskID = strings.TrimSpace(taskID)
|
||||
if strings.HasPrefix(taskID, "TASK-") && len(taskID) >= len("TASK-000") {
|
||||
num := strings.TrimSpace(strings.TrimPrefix(taskID, "TASK-"))
|
||||
if len(num) == 3 {
|
||||
allDigits := true
|
||||
for _, r := range num {
|
||||
if r < '0' || r > '9' {
|
||||
allDigits = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allDigits {
|
||||
return num
|
||||
}
|
||||
}
|
||||
}
|
||||
fallback := sanitizeTaskFolderPart(taskID)
|
||||
if fallback == "" {
|
||||
return "000"
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func ensureTaskReportPaths(t *Task) {
|
||||
|
||||
@@ -163,6 +163,40 @@ func TestTaskQueueSnapshotSortsNewestFirst(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewJobIDUsesTASKPrefixAndZeroPadding(t *testing.T) {
|
||||
globalQueue.mu.Lock()
|
||||
origTasks := globalQueue.tasks
|
||||
globalQueue.tasks = nil
|
||||
globalQueue.mu.Unlock()
|
||||
origCounter := jobCounter.Load()
|
||||
jobCounter.Store(0)
|
||||
t.Cleanup(func() {
|
||||
globalQueue.mu.Lock()
|
||||
globalQueue.tasks = origTasks
|
||||
globalQueue.mu.Unlock()
|
||||
jobCounter.Store(origCounter)
|
||||
})
|
||||
|
||||
if got := newJobID("ignored"); got != "TASK-000" {
|
||||
t.Fatalf("id=%q want TASK-000", got)
|
||||
}
|
||||
if got := newJobID("ignored"); got != "TASK-001" {
|
||||
t.Fatalf("id=%q want TASK-001", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaskArtifactsDirStartsWithTaskNumber(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
task := &Task{
|
||||
ID: "TASK-007",
|
||||
Name: "NVIDIA Benchmark",
|
||||
}
|
||||
got := filepath.Base(taskArtifactsDir(root, task, TaskDone))
|
||||
if !strings.HasPrefix(got, "007_") {
|
||||
t.Fatalf("artifacts dir=%q want prefix 007_", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAPITasksStreamReplaysPersistedLogWithoutLiveJob(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
logPath := filepath.Join(dir, "task.log")
|
||||
|
||||
Reference in New Issue
Block a user