背景

在处理多单元部署业务时,涉及到上层业务在region A调用导出接口,然后在region B中调用导入接口,把region A导出的数据导入。

在本地测试时,通过主备两套数据库来模拟。

跑单测时如果使用主数据库会造成大量脏数据,使用备数据库可以减少单测跑完后清理主数据库的麻烦。

如果按照正常流程,我们要从主库导入,然后再改改代码,然后再导入备用库。这里我们用Proxy来规避这种麻烦,在单测中一次性完成。

使用

数据库配置

修改config.local.js:

...
knex: {
  clients: {
    db1: {
        ....               // 主数据库配置
    },
    db2: {
        ...                // 备数据库配置
    },
  },
  // 是否加载到 app 上,默认开启
  app: true,
  // 是否加载到 agent 上,默认关闭
  agent: false,
},
...

挂载到Context

修改app/extend/context.js:

// ...

get db1() {
  return this.knex.get('db1');
}

get db2() {
  return this.knex.get('db2');
}

// ...

业务

// app/service/multi_region_deployments.js

* importApp(info) {
  // ...
  yield this.ctx.db1('app').insert(info);
  // ...
}

单测用例

// test/service/multi_region_deployments.test.js

// ...

describe('importApp()', () => {
  beforeEach(() => {
     ctx = app.mockContext();
  });

  it('should insert app info', function* () {
    // 从主数据库中导出数据
    const appInfo = yield ctx.service.multiRegionDeployments.exportApp(appId);

    // 通过 Proxy 将 ctx.db1 代理为 ctx.db2, 无须改变业务代码
    ctx.service.multiRegionDeployments.ctx = new Proxy(ctx.service.multiRegionDeployments.ctx, {
      get(target, property) {
        if (property === 'db1') {
          return Reflect.get(target, 'db2');
        }

        return Reflect.get(target, property);
      },
    });

    // 数据导入备数据库
    const importAppRes = yield ctx.service.multiRegionDeployments.importApp(appInfo);

    // assert something for importAppRes

    // 清理备数据库
  });
});

// ...