# 快速开始

微服务底层基于moleculer (opens new window)构建,一个Node.js快速、可扩展、容错的微服务框架

# 检出模板项目

git clone https://github.com/cool-team-official/cool-admin-moleculer-template.git

# 编写微服务业务

src/service/goods

import { App, Provide } from '@midwayjs/decorator';
import { IUserOptions } from '../interface';
import { BaseMoleculerService, CoolMoleculer } from 'midwayjs-cool-moleculer';
import { DemoAppGoodsEntity } from '../entity/goods';
import { IMidwayWebApplication } from '@midwayjs/web';

@Provide()
@CoolMoleculer({
  entity: DemoAppGoodsEntity,
  method: ['info', 'add', 'page'],
})
export class GoodsService extends BaseMoleculerService {
  @App()
  app: IMidwayWebApplication;

  async info(params) {
    console.log(this.app);
    return params;
  }
  async getUser(options: IUserOptions) {
    return {
      uid: options.uid,
      username: 'mockedName',
      phone: '12345678901',
      email: 'xxx.xxx@xxx.com',
    };
  }
}

# 修改配置文件

默认是以redis为服务之间的交流与事件传播

config.cool = {
    moleculer: {
      name: '写上你的服务名称,各个服务名称不能一样',
    },
    redis: {
      host: '192.168.10.14',
      password: '',
      port: 6379,
      db: 0,
    },
  };

# 本地调试

POST http://127.0.0.1:8001/moleculer/test

Body

{
    "name": "goods", // 服务的名称
    "service": "goodsService", // 具体的service
    "method": "page", // 调用service的方法
    "params": {  // 参数
       
    }
}

# 远程调用

import { Inject, Post, Provide } from '@midwayjs/decorator';
import { CoolController, BaseController } from 'midwayjs-cool-core';
import { Context } from 'egg';
import { Moleculer } from 'midwayjs-cool-moleculer';

/**
 * 远程调用示例
 */
@Provide()
@CoolController('/moleculer')
export class MoleculerTestController extends BaseController {
    @Inject('moleculer:moleculer')
    moleculer: Moleculer;

    @Inject()
    ctx: Context;

    /**
     * 测试
     */
    @Post('/dev')
    async dev() {
        const { name, service, method, params } = this.ctx.request.body;
        return this.moleculer.call(name, service, method, params);
    }
}

# 集群事件

# 注册事件

import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator';
import { MoleculerEvent, MoleculerEventHandler } from 'midwayjs-cool-moleculer';

/**
 * moleculer 事件处理
 */
@Provide()
@Scope(ScopeEnum.Singleton)
@MoleculerEvent()
export class MoleculerHandler {
  /**
   * 注册事件
   * @param params
   */
  @MoleculerEventHandler() // 唯一参数,eventName,事件名,可不填,默认为方法名
  async test(params) {
    console.log('收到事件test', params);
  }
}

# 事件类型

# 普通事件

多个相同的服务,只会选择其中一个执行

import { Inject, Provide } from '@midwayjs/decorator';
import {
  BaseMoleculerService,
  CoolMoleculer,
  Moleculer,
} from 'midwayjs-cool-moleculer';
import { DemoAppGoodsEntity } from '../entity/goods';

@Provide()
@CoolMoleculer({
  entity: DemoAppGoodsEntity,
  method: ['info', 'add', 'page'],
})
export class GoodsService extends BaseMoleculerService {

  @Inject('moleculer:moleculer')
  moleculer: Moleculer;

  async info(params) {
    this.moleculer.event('test1', { a: 1 }, '选填,服务名称,多个传数组');
  }
}

# 广播事件

所有服务都会收到

import { Inject, Provide } from '@midwayjs/decorator';
import {
  BaseMoleculerService,
  CoolMoleculer,
  Moleculer,
} from 'midwayjs-cool-moleculer';
import { DemoAppGoodsEntity } from '../entity/goods';

@Provide()
@CoolMoleculer({
  entity: DemoAppGoodsEntity,
  method: ['info', 'add', 'page'],
})
export class GoodsService extends BaseMoleculerService {

  @Inject('moleculer:moleculer')
  moleculer: Moleculer;

  async info(params) {
    this.moleculer.broadcastEvent('test1', { a: 1 }, '选填,服务名称,多个传数组');
  }
}

# 本地事件

只有本服务才会收到

import { Inject, Provide } from '@midwayjs/decorator';
import {
  BaseMoleculerService,
  CoolMoleculer,
  Moleculer,
} from 'midwayjs-cool-moleculer';
import { DemoAppGoodsEntity } from '../entity/goods';

@Provide()
@CoolMoleculer({
  entity: DemoAppGoodsEntity,
  method: ['info', 'add', 'page'],
})
export class GoodsService extends BaseMoleculerService {

  @Inject('moleculer:moleculer')
  moleculer: Moleculer;

  async info(params) {
    this.moleculer.broadcastLocalEvent('test1', { a: 1 });
  }
}

# 分布式事务

在微服务场景下,有可能每个服务都是连接着不同的数据库,同时也是一个比较单独的服务,所以普通的处理单体事务的方式不再适用。

目前解决分布式事务的方法多种多样:2PC(二段提交)TCC消息事务等。

cool-admin微服务分布式事务基于moleculer的事件,采用二段提交方式,协调整个集群事务。

2PC(Two-phase commit protocol),中文叫二阶段提交。 二阶段提交是一种强一致性设计,2PC 引入一个事务协调者的角色来协调管理各参与者(也可称之为各本地资源)的提交和回滚,二阶段分别指的是准备(投票)和提交两个阶段。

# 示例

import { App, Inject, Provide } from '@midwayjs/decorator';
import {
  BaseMoleculerService,
  CoolMoleculer,
  Moleculer,
  MoleculerTransaction,
} from 'midwayjs-cool-moleculer';
import { DemoAppGoodsEntity } from '../entity/goods';
import { IMidwayWebApplication } from '@midwayjs/web';
import { InjectEntityModel } from '@midwayjs/orm';
import { Repository } from 'typeorm';
import { QueryRunner } from 'typeorm';
import { TestEntity } from '../entity/test';

@Provide()
@CoolMoleculer({
  entity: DemoAppGoodsEntity,
  method: ['info', 'add', 'page'],
})
export class GoodsService extends BaseMoleculerService {
  @App()
  app: IMidwayWebApplication;

  @Inject('moleculer:moleculer')
  moleculer: Moleculer;

  /**
   * 分布式事务
   * @param params 方法参数
   * @param moleculerTransactionId 无需调用者传参, 本次事务的ID,ID会自动注入无需调用者传参
   * @param queryRunner 无需调用者传参,操作数据库,需要用queryRunner操作数据库,才能统一提交或回滚事务
   */
  // 注解启用分布式事务,参数可以指定事务类型
  @MoleculerTransaction()
  async testTransaction(
    params,
    moleculerTransactionId?,
    queryRunner?: QueryRunner
  ) {
    console.log('获得的参数', params);
    const aa = { xxx: 'goods服务' };
    await queryRunner.manager.save(TestEntity, aa);

    // 将事务id传给调用的远程服务方法
    await this.moleculer.call('order', 'goodsService', 'test', {
      moleculerTransactionId,
    });
  }
}

WARNING

使用异步操作有可能导致事务失效,@MoleculerTransaction内部已经实现了异常捕获, moleculerTransactionIdqueryRunnercommit三个参数无需调用者传参