快速实现业务需求:不重复扣费

454 阅读1分钟

docstore是一种创新的文档数据库,帮助开发者更快地完成复杂的业务需求。这个例子里,我们来看这样的一个需求:

  • 根据单号进行扣费
  • 对于重复的单号,不重复扣费

实现代码在这里:v2pro/quokka

docstore.Entity("Account", `
struct Doc {
	1: i64 amount
	2: string account_type
}
`).Command("create", `
function handle(doc, req) {
	doc.amount = req.amount;
	doc.account_type = req.account_type;
	return {};
}
`, `
struct Request {
	1: i64 amount
	2: string account_type
}
struct Response {
}
`).Command("charge", `
function handle(doc, req) {
	if (doc.account_type == 'vip') {
		if (doc.amount - req.charge < -10) {
			throw 'vip account can not below -10';
		}
	} else {
		if (doc.amount - req.charge < 0) {
			throw 'normal account can not below 0';
		}
	}
	doc.amount -= req.charge;
	return {remaining_amount: doc.amount};
}
`, `
struct Request {
	1: i64 charge
}
struct Response {
	1: i64 remaining_amount
}
`)

struct Doc 定义的是文档自身的格式,用的是thrift IDL定义语言。然后定义了两个操作,create(开户)和charge(扣费)。每个操作都定义自己的Request和Response的格式。实际的业务逻辑是用javascript写的。

调用这个docstore的代码是这样的:

func Test_charge_idempotence(t *testing.T) {
	should := require.New(t)
	execAndExpectSuccess(t, "http://127.0.0.1:9865/docstore/Account/create",
		"EntityId", "123", "CommandRequest", runtime.NewObject("amount", 100, "account_type", "vip"))
	resp := execAndExpectSuccess(t, "http://127.0.0.1:9865/docstore/Account/charge",
		"EntityId", "123", "CommandId", "xcvf", "CommandRequest", runtime.NewObject("charge", 10))
	should.Equal(90, jsoniter.Get(resp, "data", "remaining_amount").ToInt())
	resp = execAndExpectSuccess(t, "http://127.0.0.1:9865/docstore/Account/charge",
		"EntityId", "123", "CommandId", "xcvf", "CommandRequest", runtime.NewObject("charge", 10))
	should.Equal(90, jsoniter.Get(resp, "data", "remaining_amount").ToInt())
}

实际也就是执行 HTTP POST,去调用 javascript 定义的 handler。

通过这个及其简单的例子,我们可以看到docstore的一些优点:

  • 业务逻辑不用考虑并发,底层框架保证了所有的command对于一个entity来说是串行执行的。
  • 只需要写javascript的handler,以及定义schema。然后自动就有http的数据接口。避免了crud数据服务的重复开发。
  • 框架支持了CommandId,只要CommandId相同,保证了不会重复被执行,而且返回之前的返回值。也就是原生支持了幂等性。

参见:创新的主存储方案

参见:我们需要什么样的数据库