一个面向 Linux 场景的 Go 任务管理器,统一支持:
- 常驻任务(Daemon Task)
- 定时任务(Cron Task)
- 手动任务(Manual Task)
系统采用 Web 浏览器登录式管理,服务端统一调度任务;任务定义通过当前目录下的 workspaces/<task-name>/config.json 和 run.sh 管理,任务 stdout/stderr 和运行结果直接输出到 sys-task-manager 程序自身日志中。当前核心实现已经覆盖 RunAsUser 权限模型、基于子进程的安全执行机制、超时与重试、重复执行保护、最大并发限制、任务状态跟踪,以及进程内任务运行记录。
- 管理端只提供 Web 方式,不提供 CLI 管理入口。
- 用户通过浏览器访问管理后台并登录。
- 登录成功后可进行:
- 任务新增、编辑、启停
- 手动触发
manual/cron任务 - 查看任务运行状态
- 查看最近执行记录
- 查看最近运行输出
workspaces/<task-name>/run.sh是任务实际执行脚本。config.json描述任务类型、cron spec、超时、重试、执行用户和环境变量。
data/users.json存储管理员账户和密码摘要。settings.json存储本地设置。
- 登录会话
- 保存在程序内存中,仅当前进程生命周期内有效,程序重启后需要重新登录。
- 运行记录
- 保存在程序内存中,仅当前进程生命周期内可查,程序重启后清空。
推荐目录结构:
data/
├── settings.json
└── users.json
workspaces/
└── hello-world/
├── config.json
└── run.sh
示例 config.json:
{
"type": "cron",
"run_as_user": "ismdeep",
"cron": {
"spec": "*/15 * * * * *"
},
"timeout_seconds": 30,
"retry": 0,
"enabled": true
}daemon 任务只需要设置 type 为 daemon。程序启动后会自动启动该任务;任务退出后会自动重启,直到任务被禁用、删除或服务关闭。
{
"type": "daemon",
"enabled": true
}- 任务 stdout/stderr 按行写入
sys-task-manager程序自身日志。 - 任务完成后,最终状态、耗时、执行用户、错误和保留输出摘要也写入程序自身日志。
- 程序运行时不会生成每次运行的
.log、.result或runs.json文件。 - Web 页面上的运行记录来自当前进程内存,服务重启后不保留。
- 浏览器访问
/login - 服务端校验用户名和密码摘要
- 写入 session/cookie
- 登录后访问
/tasks - 页面通过 HTTP API 调用任务管理服务
- 服务端把任务定义写入
workspaces/<name>/config.json和run.sh - 任务执行时把 stdout/stderr 和运行结果写入
sys-task-manager程序自身日志,运行记录摘要保存在当前进程内存中
internal/task- 定义统一任务模型、任务类型、执行结果、任务状态。
internal/auth- 负责解析当前进程用户。
- 校验
RunAsUser是否存在。 - 根据“当前用户是否 root”执行权限判断。
internal/web- 提供浏览器登录、会话校验、任务管理页面和 HTTP API。
internal/repository- 基于本地文件持久化任务定义、管理员账号和本地设置。
- 登录会话和运行记录仅保存在进程内存中。
internal/executor- 使用
exec.CommandContext创建子进程。 - 使用
SysProcAttr.Credential{Uid, Gid}按指定用户身份执行。 - 支持
context cancel、超时、重试、标准输出/错误收集。
- 使用
internal/manager- 统一管理任务注册、状态维护、运行控制。
- 管理 daemon 启动、cron 注册,以及
manual/cron的手动触发。 - 防止同名任务重复执行,并通过信号量限制最大并发数。
internal/scheduler- 提供轻量级 cron 调度能力。
- 当前支持 5 位或 6 位 cron 表达式,以及
* /n range list等常见写法。
internal/store- 整理任务输出摘要。
- 将运行记录交给 repository 的内存记录区保存。
- 注册任务时先做结构校验。
auth.Authorizer对RunAsUser做权限校验。- Web/API 层接收请求并调用
manager.Manager。 repository将任务定义写入 workspace,将执行记录放入当前进程内存。- 执行任务时构造
context + timeout。 executor.Executor启动子进程,并通过SysProcAttr.Credential设置 UID/GID。- 执行输出按行写入
sys-task-manager程序自身日志,最终结果也写入程序自身日志。 - 页面查询 workspace 和当前进程内存中的运行记录用于展示。
- 默认执行用户:当前进程用户。
- 当前进程是
root:- 允许指定任意存在的
RunAsUser。
- 允许指定任意存在的
- 当前进程不是
root:- 只允许以当前用户执行。
- 如果指定其他用户,直接返回错误。
当前实现严格避免在主进程内直接调用 setuid/setgid,因为那会影响整个服务进程。执行器始终通过新建子进程并设置 SysProcAttr.Credential 的方式切换身份,符合服务化场景的安全实践。
.
├── data
│ ├── settings.json
│ └── users.json
├── workspaces
│ └── hello-world
│ ├── config.json
│ └── run.sh
├── go.mod
├── go.sum
├── main.go
├── internal
│ ├── auth
│ │ └── auth.go
│ ├── executor
│ │ └── executor.go
│ ├── manager
│ │ └── manager.go
│ ├── repository
│ │ └── file.go
│ ├── scheduler
│ │ └── scheduler.go
│ ├── store
│ │ └── runlog.go
│ ├── task
│ │ └── task.go
│ └── web
│ ├── server.go
│ └── templates
│ ├── login.html
│ ├── runs.html
│ └── tasks.html
workspaces/<name>/config.json
type:cron、daemon或manualdescriptionrun_as_userenabledtimeout_seconds: 仅对cron/manual生效,daemon不使用 timeoutretryenvcron.spec: cron 任务的表达式type = daemon时任务会随服务启动并持续运行,退出后自动重启
workspaces/<name>/run.sh
- 服务端会在该 workspace 目录中执行
bash run.sh - Web 新建任务时会创建默认脚本,之后可以直接编辑该文件
任务运行输出
- 每次任务运行的 stdout 和 stderr 会写入
sys-task-manager程序自身日志 - 首页显示当前正在执行任务的状态
- 历史运行记录仍可通过单独的 runs 页面查看
GET /loginPOST /loginPOST /logoutGET /tasksPOST /tasksPOST /tasks/{name}/runGET /tasks/{name}/runsGET /runs/{id}/log
每个任务至少包含以下字段:
NameDescriptionTypeRunAsUserCronExprTimeoutRetry
执行命令固定映射为 workspace 脚本:
Command.Command = "bash"Command.Args = ["run.sh"]Command.WorkDir = "workspaces/<name>"Command.Env来自config.json的env
当进程用户是 root 时,main.go 会注册:
manual-root-task:以root身份执行manual-run-as-normal-user:以普通用户(优先nobody/daemon/ubuntu)执行
manual-run-as-normal-user 会通过:
RunAsUser: "nobody"(或其他存在的普通用户)SysProcAttr.Credential{Uid, Gid}
以指定普通用户身份启动子进程。
如果当前进程不是 root,则以下场景会报错:
- 注册任务时指定
RunAsUser: "root" - 手动触发时覆盖
overrideAs = "root"
go run .默认启动后:
- HTTP 服务监听
:46808 - 默认管理员账号:
admin - 默认管理员密码:
admin123 - 示例任务会自动写入
workspaces/ - 登录会话仅保存在当前进程内存中,重启后需要重新登录
- 运行记录仅保存在当前进程内存中,重启后清空
可通过环境变量覆盖:
TASK_MANAGER_ADDRTASK_MANAGER_ADMIN_USERTASK_MANAGER_ADMIN_PASSWORD
- 使用
context管理生命周期与 graceful shutdown - 使用 goroutine + channel 做并发控制
- 提供内置 cron scheduler,离线环境也可直接编译运行
- 推荐以 Web 登录后台作为唯一管理入口
- 推荐以 workspace 目录作为任务定义来源
- 推荐以
data/*.json保存用户/设置,会话和运行记录只保存在进程内存中 - 任务状态:
pending / running / success / failed - 任务日志输出到
sys-task-manager程序自身日志,并在运行记录中保留尾部输出摘要