jeremyxu2010 / matrix-saga-go

servicecomb-saga的golang版omega
Apache License 2.0
120 stars 8 forks source link

Wrong return count from function created by MakeFunc #2

Open WillemJiang opened 5 years ago

WillemJiang commented 5 years ago

Here is a user issue https://github.com/apache/servicecomb-pack/issues/548 in ServiceComb-Pack about using go-client to connect the alpha server. @jeremyxu2010 Could you take a look at it?

2019-08-30T01:34:55.291Z error /usr/share/httpd/go/pkg/mod/github.com/grpc-ecosystem/go-grpc-middleware@v1.0.0/logging/zap/server_interceptors.go:40 finished unary call with code Internal {"serviceName": "demo", "grpc.start_time": "2019-08-30T01:34:55Z", "system": "grpc", "span.kind": "server", "grpc.service": "api.StatementGrpc", "grpc.method": "CreateStatementBatch", "error": "rpc error: code = Internal desc = reflect: wrong return count from function created by MakeFunc", "grpc.code": "Internal", "grpc.time_ms": 5.015999794006348} github.com/grpc-ecosystem/go-grpc-middleware/logging/zap.UnaryServerInterceptor.func1 /usr/share/httpd/go/pkg/mod/github.com/grpc-ecosystem/go-grpc-middleware@v1.0.0/logging/zap/server_interceptors.go:40 github.com/grpc-ecosystem/go-grpc-middleware.ChainUnaryServer.func1 /usr/share/httpd/go/pkg/mod/github.com/grpc-ecosystem/go-grpc-middleware@v1.0.0/chain.go:39 statement-svc/api._StatementGrpc_CreateStatementBatch_Handler /opt/jenkins/workspace/Youlanai-statement-svc-test/api/statement.pb.go:390 google.golang.org/grpc.(Server).processUnaryRPC /usr/share/httpd/go/pkg/mod/google.golang.org/grpc@v1.21.1/server.go:998 google.golang.org/grpc.(Server).handleStream /usr/share/httpd/go/pkg/mod/google.golang.org/grpc@v1.21.1/server.go:1278 google.golang.org/grpc.(*Server).serveStreams.func1.1 /usr/share/httpd/go/pkg/mod/google.golang.org/grpc@v1.21.1/server.go:717

jeremyxu2010 commented 5 years ago

很抱歉,由于目前在忙别的工作,确实很久没有更新该client库了。

servicecomb-pack项目的向前兼容做得很好,我试着跑了下测试用例,暂时还是可正常工作的。

从上述报错信息来看,应该是使用saga.DecorateSagaStartMethodsaga.DecorateCompensableMethod装饰的方法返回值个数不正确,被装饰的方法签名必须与声明的装饰方法签名相同,见参考测试用例

你也可以按以下指引先跑一遍测试用例看看

# 克隆并编译servicecomb-pack项目
$ git clone https://github.com/apache/servicecomb-pack.git
$ cd servicecomb-pack
$ mvn clean install -P 'mysql,!docker' -DskipTests=true

# 初始化alpha-server依赖的数据库
$ mysql -uroot -proot -h127.0.0.1 -P3306
MariaDB [(none)]> create database saga;
Query OK, 1 row affected (0.005 sec)

MariaDB [(none)]> grant all privileges on saga.* to saga@'localhost' identified by 'saga';
Query OK, 0 rows affected (0.045 sec)

MariaDB [(none)]> flush privileges;

MariaDB [(none)]> use saga
Database changed

MariaDB [saga]> source alpha/alpha-server/src/main/resources/schema-mysql.sql

MariaDB [saga]> exit
Bye

# 启动alpha-server
$ java -Dspring.profiles.active=mysql -D"spring.datasource.url=jdbc:mysql://127.0.0.1:3306/saga?useSSL=false" -D"spring.datasource.password=saga" -jar alpha/alpha-server/target/saga/alpha-server-0.6.0-SNAPSHOT-exec.jar

另开一个shell终端,执行以下命令:

# 克隆matrix-go-client项目并切换工作目录至matrix-saga-go目录
$ git clone https://github.com/jeremyxu2010/matrix-saga-go.git
$ cd matrix-saga-go
# 使用go mod下载go module依赖
$ go mod download
# 运行测试用例,可以看到转帐过程中,foo和bar的帐户余额出现了短暂的不一致,但后面又达到了最终一致性,符合saga分布式事务的设计理念
$ go run test/sagatx_demo.go
foo balance: 500, bar balance: 500
foo balance: 400, bar balance: 500
foo balance: 500, bar balance: 500
foo balance: 500, bar balance: 500
......

这个go client库是一年前做的,当时servicecomb-pack的版本还是0.2.0版本。这一年时间servicecomb-pack发展挺快,有了不少变化,实现了相当多新的功能特性(TCC模式、AlphaServer HA、SagaEnd支持等)。后续我会抽时间,参考新版本的omega逐步完善本go client库,尽可能补上相关功能特性。

xfye commented 3 years ago

我这边的原因是: 在decorator.go中,如果before func失败,那么返回值列表就是空,而被修饰的函数的返回值列表不是空,那么就会抛异常。比如当omega往alpha发送子事务启动event,但是alpha拒绝的话,那么就会出现这种情况。

    if before != nil {
        if m, ok := metadata.FromContext(ctx); ok {
            m[constants.KEY_FUNCTION_CALL_ARGS] = in
        }   
        beforeOut := beforeFunc.Call([]reflect.Value{reflect.ValueOf(ctx)})
        if !beforeOut[0].IsNil() {
            return
        }
    }
jeremyxu2010 commented 3 years ago

我这边的原因是: 在decorator.go中,如果before func失败,那么返回值列表就是空,而被修饰的函数的返回值列表不是空,那么就会抛异常。比如当omega往alpha发送子事务启动event,但是alpha拒绝的话,那么就会出现这种情况。

    if before != nil {
        if m, ok := metadata.FromContext(ctx); ok {
            m[constants.KEY_FUNCTION_CALL_ARGS] = in
        }   
        beforeOut := beforeFunc.Call([]reflect.Value{reflect.ValueOf(ctx)})
        if !beforeOut[0].IsNil() {
            return
        }
    }

@xfye 你说得对,这里如发现是错误结果,应该将错误返回,以阻止继续执行targetFunc。还有几处类似的错误处理也有问题,这两天我抽空处理一下。感谢你的反馈!