如何基于Def.sequential实现全量顺序执行任务并上报错误?
最优实现方案:全量顺序执行任务并收集错误信息
核心思路
要满足「全量顺序执行、失败不中断、错误可追溯」的需求,核心是对每个任务单独做异常捕获,串行遍历执行所有任务,并收集每个失败任务的详细信息。
通用代码实现(以Scala为例)
我们可以封装一个通用的任务执行器,负责串行执行任务、捕获异常并记录错误:
// 定义错误信息结构,绑定任务标识和异常详情 case class TaskError(taskId: String, errorMsg: String, stackTrace: String) def runTasksSequentially(tasks: (String, () => Any)*): List[TaskError] = { val errorList = scala.collection.mutable.ListBuffer[TaskError]() tasks.foreach { case (taskName, taskFunc) => try { taskFunc() // 同步执行单个任务 } catch { case e: Throwable => // 收集错误信息,包括任务名、错误消息和栈轨迹 val error = TaskError( taskId = taskName, errorMsg = e.getMessage, stackTrace = e.getStackTrace.mkString("\n") ) errorList += error } } errorList.toList } // 使用示例 val testTask1 = () => println("执行测试任务1") val testTask2 = () => throw new RuntimeException("测试任务2断言失败") val testTask3 = () => println("执行测试任务3") // 执行所有任务并获取错误列表 val errors = runTasksSequentially( "测试任务1" -> testTask1, "测试任务2" -> testTask2, "测试任务3" -> testTask3 ) // 上报/输出错误信息 errors.foreach { err => println(s"=== 任务[${err.taskId}]执行失败 ===") println(s"错误信息:${err.errorMsg}") println(s"栈轨迹:\n${err.stackTrace}\n") }
方案优势
- 严格串行执行:通过
foreach逐个调用任务,完全保证任务按顺序执行,不会并行 - 全量执行不中断:单个任务抛出的异常被即时捕获,后续任务不受影响,能完整执行所有任务
- 错误精准追溯:每个错误都绑定任务标识,能清晰定位到具体失败的测试任务,便于排查
- 灵活扩展:可根据需求调整错误收集的字段(比如添加执行时间、任务类型等),适配不同场景
针对sbt任务场景的适配(结合Def.sequential)
如果是在sbt构建系统中使用Def.sequential相关的任务定义,可以调整为适配sbt任务体系的实现:
import sbt._ // 定义sbt任务错误结构 case class SbtTaskError(taskKey: TaskKey[_], exception: Throwable) def executeAllSbtTasks(settings: Setting[_]*): Def.Initialize[Task[List[SbtTaskError]]] = Def.task { val errors = scala.collection.mutable.ListBuffer[SbtTaskError]() settings.foreach { setting => setting.key match { case taskKey: TaskKey[_] => try { taskKey.value // 执行sbt任务 } catch { case e: Throwable => errors += SbtTaskError(taskKey, e) } case _ => // 忽略非任务类型的配置 } } errors.toList } // 使用示例 val test1 = taskKey[Unit]("单元测试1") val test2 = taskKey[Unit]("单元测试2") val test3 = taskKey[Unit]("单元测试3") // 定义全量执行任务 val runAllTests = taskKey[Unit]("执行所有测试并收集错误") runAllTests := { val errors = executeAllSbtTasks(test1, test2, test3).value // 输出错误到sbt日志 val log = streams.value.log errors.foreach { err => log.error(s"任务[${err.taskKey.label}]执行失败:${err.exception.getMessage}") log.error("栈轨迹:") err.exception.getStackTrace.foreach(stack => log.error(s" $stack")) } // 若有错误,可抛出异常触发构建失败(可选) if (errors.nonEmpty) throw new RuntimeException(s"共${errors.size}个测试任务执行失败") }
内容的提问来源于stack exchange,提问作者david.perez
相关产品推荐
相关产品推荐

