描述在 grunt 中实现错误采样率动态配置

解读

面试官真正想考察的是:

  1. 你是否理解 Grunt 的任务配置模型(task → target → options)以及它“配置即代码”的哲学;
  2. 能否把“运行时变量”注入到原本静态的 Gruntfile,从而做到“同一次构建、不同采样率”;
  3. 对国内常见场景(灰度发布、AB 实验、多环境部署)是否有体感,知道为什么采样率必须“动态”而不是写死;
  4. 是否掌握 Node 侧环境变量、CLI 参数、外部 JSON、甚至是 npm_lifecycle_event 等“动态传参”手段;
  5. 能否把采样率最终落到前端产物里(例如 window.ERROR_SAMPLE),并保证 CDN 缓存安全(文件名带 hash)。

一句话:让 Grunt 在“不改动 Gruntfile 源码”的前提下,把“错误采样率”这一数值在构建时注入,并能在生产环境随时调整。

知识点

  1. Grunt 配置阶段与运行阶段分离:module.exports = function(grunt) { grunt.initConfig({…}) } 在进程启动时一次性执行完毕,因此“动态”必须在 initConfig 之前完成。
  2. process.envgrunt.option() 两种取参方式差异:前者适合 CI/CD 写入,后者适合开发者本地敲命令。
  3. grunt.template 系统:<%=%> 语法在任务运行时才求值,可用来把采样率注入到任意文本(HTML、JS、CSS)。
  4. grunt.file.write + JSON.stringify 可生成一个“运行时配置包”(如 config/error-sample.json),让前端异步拉取,实现“秒级变更,无需重新构建”。
  5. 国内 CDN 缓存策略:若采样率写进文件名(如 sentry.[sample].js)会放大缓存碎片;推荐写进文件内容 + 短链复用,同时配合 Cache-Control: no-cache 的 JSON 配置接口。
  6. 合规与灰度:国内对“用户数据出境”敏感,若采样率涉及 Sentry 等海外服务,需同时动态下发 dsn 白名单,避免硬编码。

答案

下面给出一套可直接落地的“三步法”,兼顾本地开发、线上灰度、紧急回滚三种场景,全部基于 Grunt 完成,不依赖 webpack

第一步:在 Gruntfile 最顶部把“动态采样率”收敛到一行代码

const errorSample = Number(process.env.ERR_SAMPLE || grunt.option('sample') || 0.1);

解释:

  • GitHub Actions / Jenkins / 云效 里,只要给构建任务加一行 export ERR_SAMPLE=0.01 即可;
  • 开发同学本地可敲 grunt build --sample=0.3 快速验证;
  • 兜底 0.1 防止空值导致上报风暴。

第二步:把采样率同时注入“编译期常量”和“运行时接口”,做到“双保险

grunt.initConfig({
  // 1. 注入到业务代码,用于 SDK 初始化
  replace: {
    dist: {
      src: 'src/error-tracker.js',
      dest: '.tmp/error-tracker.js',
      replacements: [{
        from: '__ERROR_SAMPLE__',
        to: errorSample
      }]
    }
  },
  // 2. 生成独立 JSON,供运维在线变更
  'file-creator': {
    config: {
      'dist/error-sample.json': function(fs, fd, done) {
        fs.writeSync(fd, JSON.stringify({ sampleRate: errorSample }));
        done();
      }
    }
  },
  // 3. 继续走原有压缩、指纹、上传 CDN 流程
  uglify: { dist: { files: { 'dist/sentry.min.js': '.tmp/error-tracker.js' } } },
  filerev: { dist: { src: 'dist/sentry.min.js' } },
  qiniu: { /* 七牛上传任务 */ }
});

说明:

  • replace 任务把占位符替换掉,前端代码里只需 Sentry.init({ sampleRate: __ERROR_SAMPLE__ })
  • error-sample.json 独立部署,运维可在 阿里云 OSS 控制台 直接编辑,5 秒生效
  • 若 JSON 接口异常,SDK 回退到编译期常量,保证可用性

第三步:在 CI/CD 脚本里给出“灰度阶梯”示例,让面试官看到你对国内发布节奏的熟悉

# 云效流水线 Stage1:金丝雀 5%
- export ERR_SAMPLE=0.05
- grunt build && grunt upload

# Stage2:观察 30 min 无异常,全量 20%
- export ERR_SAMPLE=0.2
- grunt build && grunt upload

至此,错误采样率动态配置完成:

  • 构建侧零入侵,Gruntfile 无需写死任何数字
  • 运行侧支持热变更,符合国内“白天全量、晚上灰度”的发布习惯;
  • 全程使用 Grunt 插件(grunt-contrib-uglify、grunt-text-replace、grunt-file-creator、grunt-filerev),无外部构建工具,满足题目约束。

拓展思考

  1. 如果采样率需要按用户维度(UID 白名单)而不是全局,Grunt 侧只能生成“配置表”,真正的分群逻辑应下沉到服务端网关边缘函数(阿里云 ESA),避免把用户列表打进包体。
  2. 当项目后续迁移到 Vite/Rollup 时,可把同一份 error-sample.json 保留,Grunt 与 Vite 共存做“静态资源层”构建,实现渐进式迁移
  3. 金融、政务等强合规场景,建议把 error-sample.json 放到内网接口,通过 npm 私有源 + 堡垒机 下发,避免 CDN 被外部抓取造成信息泄露
  4. 更进一步,可在 Grunt 里新增一个 custom taskgrunt.registerTask('sample:rollback', function(){ … }),一键把采样率改回 0,5 分钟内止血,让面试官看到你具备线上应急意识。