实现小程序推送服务

Annatar.He@liulishuo

2018.01.16

背景

  • 小程序比较多,大多需要推送维持次留
  • 推送服务不该和 HTTP 服务耦合
  • 处理 formid, job 比较麻烦

1. 继续现在方案
2. platform 支持
3. 新服务

消费者

  • eval(用户 script)
  • action, processor 分离
  • 运营选模板

golang

  • gRPC 支持更好
  • 自带强类型
  • 资源占用少
  • 交接成本低

nodejs

  • 前端熟悉
  • Leancloud SDK支持
  • 已有库支持(Khala)

异步任务库

mercurius

service Pusher {
    rpc CreateJob(JobRequest) returns (JobReply);
}

enum Action {
    Daily_Word_Daily_Push = 0;
    OptList_A_Todo_Push = 101;
    OptList_B_Todo_Push = 102;
    Staging_Test_Push = 999;
}

message JobRequest {
    Action action = 1;
    string openid = 2;
    int64 time = 3; // Date.now() 的 timestamp
    string data = 4; // data 是 json stringify 过的数据
}

// kue job 数据结构,参考自:
// https://github.com/Automattic/kue#json-api
message JobReply {
    int32 type = 1;
    string data = 2; // data 是 json stringify 过的数据
    int64 created_at = 3;
}

RPC 服务部分

服务推送部分

Processor

function commonProcessor(job, done) {
  const { action } = job.data as IProcessMetaData

  const processor: IWorkerProcessor = ProcessorFactory.create(job.data)
  let msg: IWechatPushMessage = null

  await processor.init()

  if (!processor.hasJob()) {
    return done(new Error(`推送已经完成,不可再次推送 ${action}`))
  }

  msg = await processor.getMessage()

  try {
    const response = await WechatService.pushMessage(msg, action2AppUid[action])
    if (response.errcode !== 0) {
      log('err', { response, msg, data: job.data })
    }
  } catch (e) {
    log('err', { e, msg, data: job.data })
  }

  await processor.done()
  done()
  return msg
}

IWorkerProcessor

abstract AVBase, MySQLBase, ...

Kue

redis: sorted set, hash, kv

测试

  • rpc 接口(85%)
  • processor(80%)

效果

  • 强类型避免低级错误
  • 向 Java/C# 学习(设计思想/模式)
  • 明确知道自己的代码在做什么
  • 写测试(or PostMortem)
  • 性能相关的问题 80/20

一些拓展

讨论

  • 这个场景下 OO 合适吗?
  • 接口会返回多种类型,应该如何描述?(any, struct)

https://github.com/Eugeny/terminus

BTW

Made with Slides.com