Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaking changes: The v1.10.0 is not fully compatible with the older QueryPrepared result #535

Open
wooln opened this issue Dec 10, 2024 · 1 comment

Comments

@wooln
Copy link
Contributor

wooln commented Dec 10, 2024

问题场景

使用csharp的sdk开发MSG模式, 抄sample中QueryPrepared代码实现,当配置的Barrier表连接串有问题(如数据库账号没有写权现),DTM状态误变成commited.

[HttpGet("msg-queryprepared")]
public async Task<IActionResult> MsgMySqlQueryPrepared(CancellationToken cancellationToken)
{
    var bb = _factory.CreateBranchBarrier(Request.Query);
    _logger.LogInformation("bb {0}", bb);
    using (MySqlConnection conn = GetConn())
    {
        var res = await bb.QueryPrepared(conn);

        return Ok(new { dtm_result = res });
    }
}

问题分析

v1.9.1时候,body不包含dtmcli三个参量ResultSuccess、ResultFailure、ResultOngoing的QueryPrepared会当成getting result failed,如http200 body:{ dtm_result: "MySql connection timeout, balabala... " },走touchCronTime。

func (t *TransGlobal) mayQueryPrepared() {
	if !t.needProcess() || t.Status == dtmcli.StatusSubmitted {
		return
	}
	body, err := t.getURLResult(t.QueryPrepared, "00", "msg", nil)
	if strings.Contains(body, dtmcli.ResultSuccess) {
		t.changeStatus(dtmcli.StatusSubmitted)
	} else if strings.Contains(body, dtmcli.ResultFailure) {
		t.changeStatus(dtmcli.StatusFailed)
	} else if strings.Contains(body, dtmcli.ResultOngoing) {
		t.touchCronTime(cronReset)
	} else {
		logger.Errorf("getting result failed for %s. error: %v body %s", t.QueryPrepared, err, body)
		t.touchCronTime(cronBackoff)
	}
}

v1.10.0后使用新的规则升级指南 1.9.x 升级到 1.10.xSDK与服务端判断 SUCCESS http:状态码 200 && 结果不包含 FAILURE|ONGOING; grpc:err == nil,上面http200示例会当成正常,走设置成Submitted。

QueryPrepared的调用链
- func (t *TransGlobal) mayQueryPrepared(ctx context.Context)
- func (t *TransGlobal) getURLResult(ctx context.Context, uri string, branchID, op string, branchPayload []byte) error
- func (t *TransGlobal) getHTTPResult(uri string, branchID, op string, branchPayload []byte) error
- func HTTPResp2DtmError(resp *resty.Response) error {

// HTTPResp2DtmError translate a resty response to error
// compatible with version < v1.10
func HTTPResp2DtmError(resp *resty.Response) error {
	code := resp.StatusCode()
	str := resp.String()
	if code == http.StatusTooEarly || strings.Contains(str, ResultOngoing) {
		return ErrorMessage2Error(str, ErrOngoing)
	} else if code == http.StatusConflict || strings.Contains(str, ResultFailure) {
		return ErrorMessage2Error(str, ErrFailure)
	} else if code != http.StatusOK {
		return errors.New(str)
	}
	return nil
}

因此,1.10.0并没有完全的兼容之前的QueryPrepared返回值。 c# 这边QueryPrepared方法只封装了BranchBarrier实现,没封装到http状态码级别。Sample中也一直按照v1.10.0之前的协议以http200靠body区分状态。
dtmcli-csharp-sample/DtmSample/DtmSample/Controllers/MsgTestController.cs at main · dtm-labs/dtmcli-csharp-sample

[HttpGet("msg-queryprepared")]
public async Task<IActionResult> MsgMySqlQueryPrepared(CancellationToken cancellationToken)
{
    var bb = _factory.CreateBranchBarrier(Request.Query);
    _logger.LogInformation("bb {0}", bb);
    using (MySqlConnection conn = GetConn())
    {
        var res = await bb.QueryPrepared(conn);

        return Ok(new { dtm_result = res });
    }
}

建议

v1.10.0发布到现在的时间跨度已经很大,已经无法做到两面都兼容,建议:

  1. 修改升级指南升级指南 1.9.x 升级到 1.10.x, 描述好这次breaking changes 0e59ccb ("change to new error protocal ok", 2022-01-10)。双向兼容仅限go sdk,其他需要自己核实

    新版本的SDK可以和新旧版本的协议兼容;新版本的服务器能够与新旧版本的协议兼容。因此理论上可以随意升级。

  2. 开发文档里明确接口调用返回值规则
  3. .net这边,封装QueryPrepared服务到http状态码的转换,并修改Sample, 避免更多人抄错
  4. 其他语言的SDK也有必要核实有没有这种状况,正常跑不会出现问题
@wooln
Copy link
Contributor Author

wooln commented Dec 13, 2024

3 .net这边,封装QueryPrepared服务到http状态码的转换,并修改Sample, 避免更多人抄错

第3点已经发起PR, 在不动原先的string res = await BranchBarrier.QueryPrepared(sqlConnection)返回字符串类型的前提下,移植了go的OrString、String2DtmError、Result2HttpJson四个方法到Utils.cs中供应用使用。bugfix(DtmSample): fix MsgMsSqlQueryPrepared return http status 200 with unrecognized error body | dtm-labs/client-csharp

todo: 修改BranchBarrier.QueryPrepared返回类型成像go版的error, 经WrapHandler处理成http返回值。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant