flipped-aurora/gin-vue-admin · error

任务名 %s 已存在

Error message

任务名 %s 已存在

What it means

checkNameUnique enforces uniqueness of task names among active (non-soft-deleted) rows at the service layer, because the soft-delete design prevents a DB-level unique index. It counts matching names (excluding the current row id when updating) and returns this error if any exist.

Source

Thrown at server/service/system/sys_timed_task.go:88

		}
	default:
		return fmt.Errorf("executorType 必须为 %s 或 %s", system.TimedTaskExecutorMethod, system.TimedTaskExecutorHTTP)
	}
	return nil
}

// checkNameUnique 软删除下不建 DB 唯一索引, 由服务层保证活跃行内唯一
func (s *TimedTaskService) checkNameUnique(ctx context.Context, name string, excludeID uint) error {
	var count int64
	db := global.GVA_DB.WithContext(ctx).Model(&system.SysTimedTask{}).Where("name = ?", name)
	if excludeID > 0 {
		db = db.Where("id <> ?", excludeID)
	}
	if err := db.Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		return fmt.Errorf("任务名 %s 已存在", name)
	}
	return nil
}

// ScheduleTask 幂等调度: 先 Clear 再按 enabled 重新注册
func (s *TimedTaskService) ScheduleTask(t system.SysTimedTask) error {
	name := timedTaskCronName(t.ID)
	global.GVA_Timer.Clear(name)
	if !t.Enabled {
		return nil
	}
	taskCopy := t // 值拷贝, 供回调闭包持有(更新任务时会整体重调度, 不会读到旧配置)
	fn := func() { s.RunTask(taskCopy, system.TimedTaskTriggerAuto) }
	var err error
	if t.WithSeconds {
		_, err = global.GVA_Timer.AddTaskByFuncWithSecond(name, t.Spec, fn, t.Name)
	} else {
		_, err = global.GVA_Timer.AddTaskByFunc(name, t.Spec, fn, t.Name)

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Choose a different, unique task name before saving
  2. If the desired name belongs to a soft-deleted row, purge/rename that old row first or pick a fresh name
  3. For updates, ensure excludeID (the task's own id) is passed so renaming to its own current name does not collide with a different row

Example fix

// before
{"name":" nightly-sync", ...} // already used by another enabled task
// after
{"name":"nightly-sync-v2", ...}
Defensive patterns

Strategy: validation

Validate before calling

var count int64
global.GVA_DB.Model(&system.SysTimedTask{}).
    Where("name = ? AND id <> ?", proposedName, excludeID).
    Count(&count)
if count > 0 {
    // surface a friendly duplicate-name message before calling the API
}

Try / catch

if err := svc.CreateTimedTask(ctx, req); err != nil {
    if strings.Contains(err.Error(), "已存在") {
        // show 'task name already in use' and prompt for a new name
        return
    }
    return err
}

Prevention

When it happens

Trigger: CreateTimedTask with a name that another live task already uses, or UpdateTimedTask renaming a task to a name owned by a different live task (excludeID filters out the task's own row).

Common situations: Cloning/duplicating a task without renaming it; two admins creating similarly named tasks concurrently (TOCTOU race between count and insert); renaming after a soft-delete left the original name visible in an old UI list; seed/init data colliding with user-created tasks.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/5c3343ac36d43790. Report an issue: GitHub.