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

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

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

实现代码在这里:v2pro/quokka

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
复制代码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的代码是这样的:

1
2
3
4
5
6
7
8
9
10
11
复制代码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相同,保证了不会重复被执行,而且返回之前的返回值。也就是原生支持了幂等性。

参见:创新的主存储方案

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

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%