开发工具箱-远程执行 RemoteRun
开发一个api服务,这个服务的功能就是,接受客户端发来的tasks,执行tasks,tasks的主要内容就是执行服务器的某些脚本; 并最好能实时返回执行日志; 另外服务端对tasks请求落库持久化,能实现管理,对执行日志进行归档处理,路径落库。
开发工具箱系列是为自己的工作减轻复杂度和自动化的工具
API服务概要设计
- 核心功能模块
任务接收与管理
提供RESTful接口接收客户端提交的脚本任务(如
POST /tasks
),支持任务优先级、超时时间、重试策略等元数据。任务唯一标识生成(如UUID),状态机设计(待执行、执行中、成功、失败、超时)。
任务执行引擎
脚本执行隔离:通过容器(如Docker)或沙箱机制隔离任务执行环境,避免资源冲突。
异步执行与队列:使用消息队列(如RabbitMQ、Kafka)或内存队列实现任务调度,支持并发控制。
实时日志处理
流式日志推送:通过SSE(Server-Sent Events)或WebSocket实时推送执行日志至客户端。
日志归档:将日志按任务ID、时间戳存储至文件系统(如MinIO)或数据库,路径信息落库(如MySQL)。
持久化与容灾
任务持久化:任务元数据(脚本路径、参数、状态)存入数据库,支持分库分表应对高并发。
异常恢复:通过定时任务扫描未完成的任务,结合重试机制保障任务最终一致性。
监控与告警
执行状态监控:记录任务耗时、成功率等指标,集成Prometheus+Grafana可视化。
异常告警:对失败任务触发邮件、钉钉等通知。
- 数据库设计
任务表(tasks)
sqlCREATE TABLE tasks ( id VARCHAR(36) PRIMARY KEY, -- 任务ID script_path VARCHAR(255) NOT NULL, -- 脚本路径 params JSON, -- 执行参数 status ENUM('pending', 'running', 'success', 'failed', 'timeout'), priority INT DEFAULT 0, -- 优先级 created_at DATETIME, updated_at DATETIME, logs_path VARCHAR(255) -- 日志存储路径 );
日志表(task_logs)
sqlCREATE TABLE task_logs ( task_id VARCHAR(36), log_time DATETIME, content TEXT, FOREIGN KEY (task_id) REFERENCES tasks(id) );
- API接口设计
- 提交任务
POST /tasks
请求体:{ "script_path": "/scripts/backup.sh", "params": {"dir": "/data"}, "priority": 1 }
- 查询任务状态
GET /tasks/{id}
- 实时日志订阅
GET /tasks/{id}/logs
(SSE流)
基于Go实现API服务的详细设计
一、核心模块实现方案
任务接收与管理模块
RESTful API设计
使用Gin框架实现任务提交接口(
POST /tasks
)和状态查询接口(GET /tasks/{id}
),支持JSON格式请求体,包含脚本路径、参数、优先级等元数据。
示例代码片段:gorouter := gin.Default() router.POST("/tasks", func(c *gin.Context) { var task TaskRequest if err := c.ShouldBindJSON(&task); err != nil { c.JSON(400, gin.H{"error": "Invalid request"}) return } taskID := generateUUID() // 落库并加入队列 c.JSON(201, gin.H{"id": taskID}) })
任务执行引擎
并发控制与隔离
采用Worker Pool模式,通过缓冲通道(
chan Task
)控制并发数(如限制10个并行任务)。结合os/exec
执行脚本,使用Docker容器或syscall
的Chroot
隔离执行环境,防止资源冲突。 示例代码片段:gotype WorkerPool struct { tasks chan Task wg sync.WaitGroup } func (wp *WorkerPool) Start() { for i := 0; i < 10; i++ { wp.wg.Add(1) go func() { defer wp.wg.Done() for task := range wp.tasks { cmd := exec.CommandContext(task.Ctx, "sh", task.ScriptPath) output, _ := cmd.CombinedOutput() // 推送日志并更新状态 } }() } }
实时日志推送
SSE(Server-Sent Events)实现
通过Gin的
Stream
方法推送日志流,客户端订阅GET /tasks/{id}/logs
接口。每条日志以data: {log}\n\n
格式发送,支持自动重连。 示例代码片段:gofunc (c *gin.Context) { taskID := c.Param("id") c.Stream(func(w io.Writer) bool { log := <-getLogChannel(taskID) // 从日志通道读取 fmt.Fprintf(w, "data: %s\n\n", log) return true }) }
持久化与容灾
数据库设计
使用MySQL或PostgreSQL存储任务元数据和日志路径,表结构如下:
sqlCREATE TABLE tasks ( id VARCHAR(36) PRIMARY KEY, script_path VARCHAR(255), status ENUM('pending', 'running', 'success', 'failed'), created_at DATETIME, logs_path VARCHAR(255) );
结合GORM库实现ORM映射,事务保证数据一致性。
二、Go语言优势与关键技术选型
高并发与轻量化
Goroutine调度:单机支持万级并发任务,通过
runtime.GOMAXPROCS
优化CPU绑定任务。编译为二进制:生成<10MB的独立可执行文件,适合Docker容器化部署(Alpine镜像仅~5MB)。
关键库与工具链
框架:Gin(API路由)、Asynq(任务队列)。
日志管理:Zap高性能日志库,结合Lumberjack实现日志轮转。
监控:Prometheus客户端收集任务耗时、成功率指标,Grafana可视化。
三、扩展建议
安全增强
脚本执行前校验数字签名,防止恶意代码注入。
使用
seccomp
或gVisor
加强容器隔离。
任务优先级调度
基于Redis的Sorted Set实现动态优先级队列,高优先级任务插队执行。日志脱敏与审计
在日志输出层动态过滤敏感信息(如密钥),记录操作审计日志。
四、参考实现代码结构
.
├── main.go # API入口
├── internal
│ ├── api # Gin路由层
│ ├── task # 任务调度逻辑
│ ├── persistence # 数据库ORM(GORM)
│ └── sse # SSE推送模块
├── scripts # 可执行脚本目录
└── Dockerfile # 多阶段构建优化镜像