跳到正文
Kale的数字花园
目录 文章
/11 分钟/7 阅读/0 评论

DevOps CI/CD 流水线与 AI 代码审查平台:事件驱动架构 + 智能评审

1. **@Async + 线程池隔离**:AI 审查和 Jenkins 轮询分别走独立线程池,互不阻塞 2. **事件处理器可扩展**:新增 DeployTaskEventHandler 实现类即可扩展通知渠道 3. **Prompt 模

1. 背景与痛点

业务背景

场景一:代码审查效率低下

  • 研发团队每日产生大量 Merge Request(MR),人工 Review 耗时且容易遗漏
  • 不同项目(Java/Go/前端)审查要点不同,人工难以保持一致标准
  • 审查结果通知依赖人工截图/复制,流程割裂

场景二:CI/CD 部署流程分散

  • Jenkins 构建、k8s 部署、飞书通知分散在多个系统,缺乏统一视图
  • 部署状态需要人工轮询 Jenkins 页面,效率低下
  • 分支到环境的映射(dev/release/master)需要人工记忆和操作

场景三:Git 运维自动化需求

  • 工蜂 Git 全量/增量备份到阿里云 OSS / 腾讯云 COS
  • CronJob 执行超时/漏调度需要监控告警
  • NAS 临时目录、ClickHouse 日志需要定时清理

技术痛点

痛点一:多语言异构系统协同

  • 代码侧使用 Go(定时任务)+ Java(业务逻辑)
  • 两套独立服务,独立部署,通过 REST API 轻量级交互
  • 需要统一的消息通知通道(飞书)

痛点二:AI 审查的 Prompt 工程挑战

  • 不同语言(Java/Go/前端)审查要点差异大
  • 需要在 Prompt 中注入项目类型上下文
  • 过滤无关文件(配置文件、二进制依赖)避免干扰

痛点三:Webhook 事件类型繁多

  • Push Hook / Tag Push Hook / Merge Request Hook 三种事件
  • 需要 Token 验证、分支名解析、提交人/处理人判断
  • MR 触发条件:仅 release 分支合并 或 hotfix 到 master

痛点四:Jenkins 轮询效率

  • 构建是异步的,需要轮询等待结果
  • 轮询间隔和超时时间需要权衡(太短怕频率太高,太长怕用户体验差)

2. 技术方案

整体架构(事件驱动 + 异步处理)

┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                              事件入口层(Webhook)                                        │
│                                                                                         │
│  工蜂 Git Webhook → /tgit/events                                                        │
│      ├─ X-Event=Push Hook       → 解析分支,触发 Jenkins 构建                          │
│      ├─ X-Event=Tag Push Hook  → 触发同名 Tag 镜像构建                                  │
│      └─ X-Event=Merge Request Hook → 触发 AI 代码审查 + 飞书通知                        │
└─────────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                              Java 服务层(codo-devops)                                 │
│                                                                                         │
│  TencentGitController(事件接收入口)                                                   │
│      │                                                                                 │
│      ├─ TencentGitService(同步):获取 MR 详情、变更文件、文件内容                      │
│      │                                                                                 │
│      └─ TencentGitAsyncService(异步):AI 代码审查核心逻辑                              │
│              │                                                                         │
│              ├─ 项目类型检测(listRepositoryTree)                                       │
│              ├─ 文件过滤(排除配置/二进制)                                              │
│              ├─ Prompt 构建(语言特定审查要点)                                          │
│              └─ ChatGPT/Claude API 调用                                                 │
│                                                                                         │
│  JenkinsService(异步):构建触发 + 轮询等待 + 状态回调                                 │
│      │                                                                                 │
│      └─ DeployTaskStore(内存存储)→ DeployTaskEventHandler(事件驱动)                │
│              │                                                                         │
│              └─ NotifyDeployTaskEventHandlerImpl → FeishuMessageService → 飞书通知     │
└─────────────────────────────────────────────────────────────────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                              Go 服务层(codo-devops-tasks)                             │
│                                                                                         │
│  定时任务(robfig/cron + time.Ticker)                                                  │
│      ├─ 工蜂 Git 备份(全量/增量 → OSS/COS)                                           │
│      ├─ NAS 临时目录清理                                                                │
│      ├─ ClickHouse 日志清理                                                             │
│      ├─ K8s CronJob 监控(超时/漏调度告警)                                            │
│      └─ 健康检查(HTTP → 飞书告警)                                                    │
│                                                                                         │
│  分布式锁(Redis redsync):保证任务幂等性                                               │
└─────────────────────────────────────────────────────────────────────────────────────────┘

AI 代码审查流程

MR Open/Update 事件
        ↓
shouldProcessChanges() 过滤:仅 release 合并 或 hotfix→master
        ↓
getMergeRequestChanges() 获取变更文件列表
        ↓
shouldReviewFile() 过滤:
  - 排除:pom.xml, application*.yml, go.sum, node_modules
  - 排除:.class, .jar, 二进制文件
        ↓
获取每个变更文件的完整内容
        ↓
detectProjectKind() 检测项目类型(Java/Golang/React/Python)
        ↓
buildPromptBody() 构建 Prompt:
  - 通用审查要点(代码风格、命名、安全性)
  - 语言特定审查要点(Java: 线程安全/空指针/资源释放)
  - 输出格式要求(总结 + 分点 + 等级标注)
        ↓
ChatGPTService.responses() 调用 AI
        ↓
extractResponsesText() 提取回复
        ↓
FeishuMessageService 发送飞书通知(@提交人 + @处理人)

Jenkins CI/CD 流程

Push 事件 → triggerJenkinsJob(projectName, branchName, imageVersion)
        ↓
JenkinsService.triggerJenkinsBuild() @Async
        ↓
buildAndGetBuildQueueId() → 获取 queueId
        ↓
progressJob() 轮询:
  ├─ getLastBuildNumber(queueId) 获取实际 BuildNumber
  ├─ fetchBuildInfo() 轮询直到 building=false
  └─ 根据 result 处理:
        ├─ SUCCESS → DeployTaskStore.addDeployTask(PENDING)
        │       ↓ triggerHandlers()
        │       ↓ NotifyDeployTaskEventHandler → 飞书通知
        │
        ├─ FAILURE → 飞书通知 "❌ 构建失败"
        └─ ABORTED → 飞书通知 "➖ 构建中断"

3. 实现细节

模块一:Webhook 事件路由(TencentGitController)

@PostMapping("/tgit/events")
public String handleEvents(
    @RequestHeader("X-Event") String eventType,
    @RequestHeader("X-Token") String token,
    @RequestBody String eventBody) {

    // Token 验证
    if (!Objects.equals(token, TGIT_HOOK_TOKEN)) {
        return "token not match";
    }

    ObjectMapper objectMapper = new ObjectMapper();
    if ("Push Hook".equals(eventType)) {
        PushHookEvent event = objectMapper.readValue(eventBody, PushHookEvent.class);
        return handlePushEvents(event);
    } else if ("Tag Push Hook".equals(eventType)) {
        TagPushHookEvent event = objectMapper.readValue(eventBody, TagPushHookEvent.class);
        return handleTagPushEvents(event);
    } else if ("Merge Request Hook".equals(eventType)) {
        MergeRequestHookEvent event = objectMapper.readValue(eventBody, MergeRequestHookEvent.class);
        return handleMergeRequestEvents(event);
    }
    return "unknown event type";
}

分支名解析(refs/heads/dev → dev):

private static Optional<String> getBranchName(Pattern pattern, String ref) {
    var matcher = pattern.matcher(ref);
    if (matcher.matches()) {
        return Optional.of(matcher.group(1));  // 提取分组1
    }
    return Optional.empty();
}

// 使用
Pattern BRANCH_PATTERN = Pattern.compile("refs/heads/(.*)");
Pattern TAG_PATTERN = Pattern.compile("refs/tags/(.*)");

模块二:MR 触发条件判断

private boolean shouldProcessChanges(MergeRequestInfo mergeRequest) {
    String sourceBranch = mergeRequest.sourceBranch();
    String targetBranch = mergeRequest.targetBranch();

    // 合并到 release 分支 → 审查
    boolean isReleaseBranch = targetBranch != null && targetBranch.startsWith("release");

    // hotfix 合并到 master → 审查
    boolean isHotfix = targetBranch != null && targetBranch.startsWith("master")
        && sourceBranch != null && sourceBranch.startsWith("hotfix");

    return isReleaseBranch || isHotfix;
}

模块三:AI 审查 Prompt 构建(核心)

private String buildPromptBody(ProjectKind projectKind,
                               MergeRequestInfo mr,
                               List<MergeRequestChangeFile> files,
                               Map<String, String> fileContentMap) {

    StringBuilder prompt = new StringBuilder();

    // 1. 项目类型与审查要点
    prompt.append(switch (projectKind) {
        case JAVA -> """
            【项目类型: Java】额外审查要点:
            - 线程安全: HashMap/ArrayList vs ConcurrentHashMap
            - 空指针风险: Optional、null 检查
            - 资源释放: try-with-resources、Stream 关闭
            - 性能: N+1 查询、循环内 DB 操作
            - 安全: SQL 注入、XSS、敏感信息硬编码
            - 单元测试: 核心逻辑是否有覆盖
            """;
        case GOLANG -> """
            【项目类型: Go】额外审查要点:
            - 错误处理: 是否 defer 关闭资源、error 是否被忽略
            - 并发安全: goroutine 泄露、channel 关闭
            - 指针 nil 检查、slice 容量预分配
            """;
        case REACT -> """
            【项目类型: React/前端】额外审查要点:
            - 依赖注入: 是否存在循环依赖
            - 状态管理: useState/useEffect 滥用
            - 性能: 避免不必要的重渲染
            """;
        default -> "";
    });

    // 2. MR 基本信息
    prompt.append("\n【MR 信息】\n");
    prompt.append("标题: ").append(mr.title()).append("\n");
    prompt.append("源分支: ").append(mr.sourceBranch()).append("\n");
    prompt.append("目标分支: ").append(mr.targetBranch()).append("\n");

    // 3. 变更文件列表
    prompt.append("\n【变更文件】\n");
    for (var file : files) {
        prompt.append("- ").append(file.newPath()).append("\n");
    }

    // 4. 变更详情(截取 diff)
    prompt.append("\n【变更详情】\n");
    prompt.append(buildDiffSection(files));

    // 5. 输出格式要求
    prompt.append("""
        \n【输出要求】
        1. 先给整体总结(代码质量、风险等级、建议)。
        2. 分点列出问题(标明【严重】【建议】【提示】等级)。
        3. 每个问题说明:文件路径 + 行号 + 问题描述 + 修改建议。
        4. 若没有问题,也需说明"已检查哪些维度,无明显问题"。
        """);

    return prompt.toString();
}

模块四:Jenkins 轮询与状态回调

@Async
public void triggerJenkinsBuild(String userId, String projectName,
                                String branchName, String imageVersion, boolean sendNotify) {
    // 1. 触发构建,获取 queueId
    final Integer queueId = buildAndGetBuildQueueId(projectName, branchName, imageVersion);

    // 2. 轮询构建结果
    progressJob(userId, projectName, queueId, branchName, sendNotify);
}

private void progressJob(String userId, String projectName, Integer queueId,
                         String branchName, boolean sendNotify) {
    // 等待队列中的任务变为实际构建
    final Integer lastBuildNumber = getLastBuildNumber(queueId);

    // 轮询直到构建结束
    BuildInfo buildInfo;
    do {
        try {
            Thread.sleep(3_000);  // 3 秒间隔
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        buildInfo = jenkinsClient.api().jobsApi()
            .getBuildInfo(projectName, lastBuildNumber);
    } while (buildInfo.building());  // building=true 表示还在执行

    // 3. 根据结果处理
    if ("SUCCESS".equals(buildInfo.result())) {
        // 映射到环境,创建部署任务
        branchEnvMapper.toEnv(branchName).ifPresentOrElse(env -> {
            String deploymentName = deployJobMapper.toDeployment(projectName);
            deployTaskStore.addDeployTask(new DeployTask(
                queueId, deploymentName, Instant.now(),
                DeployStatus.PENDING, env, null, userId));
        });
    }

    // 4. 发送通知
    if (sendNotify) {
        feishuMessageService.sendMessageToChat(buildResultMessage(...), ...);
    }
}

模块五:Go 分布式锁实现

type Locker struct {
    key   string
    mutex *redsync.Mutex
}

// 在分布式锁保护下执行任务
func (lck *Locker) Run(task func() error) error {
    // 1. 获取锁(尝试1次,30秒过期)
    if err := lck.mutex.Lock(); err != nil {
        return err
    }

    // 2. 启动 goroutine 定期延长锁(每10秒续约一次)
    ticker := time.NewTicker(10 * time.Second)
    go func() {
        for {
            select {
            case <-ticker.C:
                lck.mutex.Extend()  // 延长锁过期时间
            }
        }
    }()

    // 3. 执行任务
    bizErr := task()

    // 4. 释放锁
    ticker.Stop()
    lck.mutex.Unlock()

    return bizErr
}

// 锁 Key 常量
const (
    RedisKeyNasCleaner    = "codo:devops:tasks:nas:cleaner"
    RedisKeyBackupTgit    = "codo:devops:tasks:backup:tgit"
    RedisKeyHealthCheck   = "codo:devops:tasks:health-check"
)

模块六:飞书通知消息体

// Go 侧飞书富文本消息结构
public class PostRichTextRequest {
    String chatId;  // "oc_codo-devops"
    RichTextContent content;
}

public class RichTextContent {
    Post post;
}

public class Post {
    Body zh_cn;  // 中文内容
}

public class Body {
    String title;
    List<List<Item>> content;  // [[Item, Item], [Item]] 多行多元素
}

public class Item {
    String tag;      // "text" | "at"
    String text;     // 文本内容
    String userId;   // at 用户时使用
}

// 发送消息
public void sendMessageToChat(String message, Collection<String> atUserIds) {
    List<Item> items = new ArrayList<>();
    items.add(Item.text(message));  // 文本行
    for (var userId : atUserIds) {
        items.add(Item.at(userId));  // @用户
    }
    var request = new PostRichTextRequest();
    request.setChatId("oc_codo-devops");
    request.setContent(new RichTextContent(...));
    feishuService.postRichText(request);
}

4. 技术栈与亮点归纳

技术栈清单

分类 技术
Java 服务 Spring Boot 2.6.6、Spring Cloud OpenFeign、@Async 异步处理
Go 服务 Go 1.23.4、spf13/cobra CLI、robfig/cron 定时任务
分布式锁 Redis redsync(Go)、Redisson(Java)
外部集成 Jenkins REST API、工蜂 Git API、ChatGPT/Claude API、飞书 API
消息队列 本地 @Async 线程池(Java)、Goroutine + Channel(Go)
配置管理 JSON 配置(Go)、application.yml(Java)

技术亮点

  • 事件驱动架构:Webhook 触发 → 异步处理 → 飞书通知,全程无阻塞
  • 分层事件处理器:DeployTaskEventHandler 接口化,新增处理器无需修改核心逻辑
  • 内存状态存储:DeployTaskStore 用 LinkedHashMap 存储部署任务,避免数据库依赖
  • 分布式锁续约机制:Go 侧定期 Extend() 防止长任务执行中锁过期
  • Prompt 工程:根据项目类型注入不同审查要点,提高 AI 审查针对性
  • Token 验证 + 分支过滤:双重保障,只处理预期的 MR 事件

5. 难点与亮点剖析

业务难点

难点一:跨语言异构系统协同

  • Go 和 Java 两套独立服务,通过 REST API 交互
  • 需要统一的消息通知通道(飞书)和用户身份映射
  • 健康检查需要 Go 侧 HTTP 调用 Java 侧接口

难点二:AI 审查的上下文获取

  • Webhook 只推送事件,不含文件内容
  • 需要调用工蜂 API 依次获取:MR 详情 → 变更文件列表 → 每个文件内容
  • 涉及多次 API 调用,需要处理限流和失败重试

难点三:Jenkins 轮询的时效性

  • 构建时间不确定(1 分钟到 30 分钟不等)
  • 轮询间隔太短:浪费资源、可能触发限流
  • 轮询间隔太长:用户体验差(等很久没反馈)

技术难点

技术难点一:Webhook 安全验证

  • 工蜂 Webhook 使用固定 Token 验证
  • 需要防御重放攻击(可在 Redis 中记录已处理事件 ID)

技术难点二:文件过滤策略

  • 排除:pom.xml、application*.yml、go.sum、node_modules
  • 排除:.class、.jar、.bin 等二进制文件
  • 需要根据文件后缀或 MIME 类型判断

技术难点三:MR 审查触发条件

  • 需要区分:MR Open、MR Update、MR Merge
  • 只需处理:release 分支合并、hotfix→master
  • 分支名解析:refs/heads/dev → dev

实现亮点

  1. @Async + 线程池隔离:AI 审查和 Jenkins 轮询分别走独立线程池,互不阻塞
  2. 事件处理器可扩展:新增 DeployTaskEventHandler 实现类即可扩展通知渠道
  3. Prompt 模板化:语言特定审查要点抽取为独立方法,便于维护和扩展
  4. 续约锁防止长任务:10 秒续约间隔保证 30 秒过期锁可用于任意时长任务

6. 替代方案对比

方案一:GitLab CI / GitHub Actions 原生 AI 审查

  • 实现:在 CI pipeline 中调用 AI API
  • 优劣:与 Git 深度集成,但只能审查合并后的代码,无法审查 MR
  • 结论:本团队使用工蜂 Git,自研平台灵活性更高

方案二:轮询 vs WebSocket

  • 轮询方案:定时请求 Jenkins API 获取状态(当前方案)
  • 优劣:实现简单,但有延迟;WebSocket 实时但实现复杂,需要 Jenkins 插件支持
  • 结论:当前业务场景轮询足够(3 秒间隔可接受)

方案三:Go + Java 合体 vs 分离

  • 分离部署:当前方案(Go 定时任务 + Java 业务逻辑)
  • 优劣:职责分离、独立扩缩容;但增加运维复杂度
  • 合体:用 Java 重写定时任务,或用 Go 重写整个平台
  • 结论:团队 Go 和 Java 能力都有,分离更符合微服务原则

7. 技术选型与方案抉择复盘

选型思路

  • AI API:ChatGPT / Claude Codex,企业内网部署 AI Gateway,统一鉴权
  • Jenkins:团队已有 Jenkins 集群,复用现有 CI 能力
  • 语言选择:Java 为主业务语言,Go 用于运维工具(轻量、部署简单)
  • 消息通知:统一走飞书,与团队协作工具一致

优点

  • 事件驱动,低耦合:Webhook 触发后异步处理,各环节独立
  • AI 审查标准化:不同语言统一 Prompt 模板,审查质量一致
  • 部署状态可视化:DeployTaskStore 提供统一视图

缺点 / 已知不足

  • Jenkins 轮询效率:3 秒间隔在构建高峰期可能产生较多无用请求
  • 内存存储风险:DeployTaskStore 在内存中,Pod 重启丢失
  • AI 审查局限:依赖 Prompt 质量,无法理解业务逻辑

可优化点

  • Jenkins 插件化:改用 Jenkins 插件 + WebSocket,替代轮询
  • 持久化 DeployTaskStore:接入 Redis 或 MySQL,支持多实例
  • AI 审查结果存储:存入 ClickHouse,支持历史查询和趋势分析
  • 支持更多 MR 事件:如 Code Review Comment 事件

8. 成果与数据

  • AI 审查覆盖率:release 分支 MR 100% 自动审查
  • 审查响应时间:MR Open → 飞书通知 < 2 分钟(取决于 AI API 响应速度)
  • Jenkins 构建触发:Push 事件 → 构建开始 < 5 秒
  • 部署状态通知:构建完成 → 飞书通知 < 3 秒
  • Go 侧任务稳定性:分布式锁保护,零重复执行
  • 健康检查:每 10 分钟检查一次,异常 < 5 分钟告警

9. 面试题清单

  1. 【基础】@Async 注解的原理是什么?线程池配置不当会有什么后果?
    • 考察点:Spring 异步执行原理、ThreadPoolTaskExecutor 配置、拒绝策略
  2. 【基础】Jenkins REST API 如何触发构建?如何获取构建状态?
    • 考察点:buildWithParameters、queueApi、getBuildInfo、轮询机制
  3. 【进阶】Webhook 安全如何保证?Token 验证和重放攻击防护?
    • 考察点:固定 Token、事件 ID 去重、时间戳校验
  4. 【进阶】分布式锁的续约机制是如何实现的?为什么要续约?
    • 考察点:redsync mutex、Extend()、任务执行时间 > 锁过期时间
  5. 【进阶】@Async 方法抛异常了,调用方能感知到吗?如何处理?
    • 考察点:异步异常无法传播、Future/CompletableFuture 接收、异常回调
  6. 【进阶】设计一个事件处理器接口,需要考虑哪些要素?
    • 考察点:支持状态集合、处理方法、异常隔离、处理器顺序
  7. 【原理】Go 的 Goroutine 和 Java 的线程有什么区别?轻量级体现在哪?
    • 考察点:GMP 模型、栈大小动态增长、上下文切换成本
  8. 【原理】Redis 分布式锁的 setnx + expire 有什么坑?redsync 如何解决的?
    • 考察点:setnx 和 expire 非原子、锁误删除、redsync 的 Lua 脚本保证
  9. 【设计】如果要在 MR 评论中直接回复 AI 审查意见,如何设计?
    • 考察点:工蜂 API 能力、评论内容格式化、@用户交互
  10. 【设计】AI 审查的 Prompt 如何设计才能提高审查质量?
    • 考察点:few-shot 示例、输出格式约束、语言特定要点注入
  11. 【延伸】如果要支持 GitHub/GitLab,如何改造架构?
    • 考察点:抽象 Git 提供商接口、事件模型统一、API 差异适配

10. 简历提炼版

设计并实现DevOps CI/CD 流水线平台,基于事件驱动架构,Webhook 触发后异步执行 AI 代码审查 + Jenkins 构建 + 飞书通知全流程;自研 Prompt 工程模块,根据项目类型(Java/Go/前端)注入差异化审查要点;DeployTaskStore 采用内存存储 + 事件处理器接口化,支持多渠道通知一键扩展;Go 侧实现分布式锁续约机制,保障定时任务零重复执行;覆盖 release/hotfix 分支 MR 100% 自动化审查,响应时间 < 2 分钟。


关键源码路径

Java 服务层(codo-devops)

文件 路径
Webhook 控制器 codo-devops/src/main/java/com/codo/tech/devops/controller/tgit/TencentGitController.java
工蜂服务 codo-devops/src/main/java/com/codo/tech/devops/service/tgit/TencentGitService.java
AI 审查核心 codo-devops/src/main/java/com/codo/tech/devops/service/tgit/TencentGitAsyncService.java
ChatGPT 服务 codo-devops/src/main/java/com/codo/tech/devops/service/chatgpt/ChatGPTService.java
Jenkins 服务 codo-devops/src/main/java/com/codo/tech/devops/service/JenkinsService.java
部署任务存储 codo-devops/src/main/java/com/codo/tech/devops/service/jenkins/DeployTaskStore.java
事件处理器 codo-devops/src/main/java/com/codo/tech/devops/service/jenkins/DeployTaskEventHandler.java
通知处理器 codo-devops/src/main/java/com/codo/tech/devops/service/jenkins/NotifyDeployTaskEventHandlerImpl.java
飞书服务 codo-devops/src/main/java/com/codo/tech/devops/service/feishu/FeishuMessageService.java
分支环境映射 codo-devops/src/main/java/com/codo/tech/devops/service/jenkins/BranchEnvMapper.java
部署任务模型 codo-devops/src/main/java/com/codo/tech/devops/service/jenkins/domain/DeployTask.java
部署状态枚举 codo-devops/src/main/java/com/codo/tech/devops/service/jenkins/domain/DeployStatus.java

Go 服务层(codo-devops-tasks)

文件 路径
HTTP 服务器入口 codo-devops-tasks/server/server.go
配置加载 codo-devops-tasks/config/config.go
定时任务启动器 codo-devops-tasks/job/job_starter.go
分布式锁 codo-devops-tasks/lock/lock.go
锁 Key 常量 codo-devops-tasks/lock/paths.go
飞书客户端 codo-devops-tasks/feishu/feishu_client.go
工蜂备份 codo-devops-tasks/tasks/tgit/backupgongfeng/backup_gongfeng.go
CronJob 监控 codo-devops-tasks/tasks/cronjobwatcher/cronjob_watcher.go
健康检查 codo-devops-tasks/tasks/healthcheck/health_check.go
相关阅读

8 分钟

通用异常体系与全局响应封装

ERP 系统是一个高度分层的微服务架构: 任何一层出错,最终都要以**统一的格式**返回给前端,任何一环抛出的异常,都要能被**全局捕获并标准化处理**。 集团内用户包含中文、英文等多语言,错误信息硬编码无法切换。 跨服务调用时,服务 B

面试#基础架构7 阅读 · 0 评论

评论需要登录。生产环境使用 GitHub 登录,本地可前往 登录页 使用开发登录。

还没有评论,来抢沙发。