From 15b2bde074e6ed88d582adb8d1b1e45a2ecd19e7 Mon Sep 17 00:00:00 2001 From: Yunjin Xu Date: Fri, 24 Apr 2026 16:28:09 +0800 Subject: [PATCH] Add SetRequestTimeout method to Msg class --- src/Dtmcli/Msg/Msg.cs | 11 +++ tests/Dtmcli.IntegrationTests/ITTestHelper.cs | 20 ++++ tests/Dtmcli.IntegrationTests/MsgHttpTest.cs | 93 +++++++++++++++++++ tests/Dtmcli.Tests/MsgTests.cs | 39 ++++++++ 4 files changed, 163 insertions(+) diff --git a/src/Dtmcli/Msg/Msg.cs b/src/Dtmcli/Msg/Msg.cs index 4d93909..c28b075 100644 --- a/src/Dtmcli/Msg/Msg.cs +++ b/src/Dtmcli/Msg/Msg.cs @@ -130,6 +130,17 @@ public Msg SetRetryInterval(long retryInterval) this._transBase.RetryInterval = retryInterval; return this; } + + /// + /// Set timeout for sub branch, unit is second + /// + /// timeout to fail + /// + public Msg SetRequestTimeout(long requestTimeout) + { + this._transBase.RequestTimeout = requestTimeout; + return this; + } /// /// Set branch headers for trans diff --git a/tests/Dtmcli.IntegrationTests/ITTestHelper.cs b/tests/Dtmcli.IntegrationTests/ITTestHelper.cs index 3d70854..597fd43 100644 --- a/tests/Dtmcli.IntegrationTests/ITTestHelper.cs +++ b/tests/Dtmcli.IntegrationTests/ITTestHelper.cs @@ -24,6 +24,20 @@ public static async Task GetTranStatus(string gid) return string.Empty; } + + public static async Task GetTran(string gid) + { + var resp = await _client.GetAsync($"{DTMHttpUrl}/api/dtmsvr/query?gid={gid}").ConfigureAwait(false); + + if (resp.IsSuccessStatusCode) + { + var content = await resp.Content.ReadAsStringAsync(); + var res = System.Text.Json.JsonSerializer.Deserialize(content); + return res; + } + + return null; + } public class QueryResult { @@ -35,6 +49,12 @@ public class TransGlobalStore { [System.Text.Json.Serialization.JsonPropertyName("status")] public string Status { get; set; } + + [System.Text.Json.Serialization.JsonPropertyName("request_timeout")] + public long RequestTimeout { get; set; } + + [System.Text.Json.Serialization.JsonPropertyName("timeout_to_fail")] + public long TimeoutToFail { get; set; } } diff --git a/tests/Dtmcli.IntegrationTests/MsgHttpTest.cs b/tests/Dtmcli.IntegrationTests/MsgHttpTest.cs index 1dbab25..f58c472 100644 --- a/tests/Dtmcli.IntegrationTests/MsgHttpTest.cs +++ b/tests/Dtmcli.IntegrationTests/MsgHttpTest.cs @@ -91,4 +91,97 @@ public async Task Submit_With_Delay_Should_Succeed_Later() status = await ITTestHelper.GetTranStatus(gid); Assert.Equal("succeed", status); } + + [Fact] + public async Task SetRequestTimeoutTest_default() + { + var provider = ITTestHelper.AddDtmHttp(); + var transFactory = provider.GetRequiredService(); + + var gid = "msgTestGid" + Guid.NewGuid().ToString(); + var msg = transFactory.NewMsg(gid); + // msg.SetRequestTimeout(30); + msg.EnableWaitResult(); + var req = ITTestHelper.GenBusiReq(false, false); + var busiUrl = ITTestHelper.BuisHttpUrl; + msg.Add(busiUrl + "/busi.Busi/TransOut", req) + .Add(busiUrl + "/busi.Busi/TransIn", req); + + await msg.Prepare(busiUrl + "/busi.Busi/QueryPrepared_404"); + await msg.Submit(); + + var trans = await ITTestHelper.GetTran(gid); + Assert.Equal("succeed", trans.Transaction.Status); + Assert.Equal(0, trans.Transaction.RequestTimeout); + } + + [Fact] + public async Task SetRequestTimeoutTest_30s() + { + var provider = ITTestHelper.AddDtmHttp(); + var transFactory = provider.GetRequiredService(); + + var gid = "msgTestGid" + Guid.NewGuid().ToString(); + var msg = transFactory.NewMsg(gid); + msg.SetRequestTimeout(30); + msg.EnableWaitResult(); + var req = ITTestHelper.GenBusiReq(false, false); + var busiUrl = ITTestHelper.BuisHttpUrl; + msg.Add(busiUrl + "/busi.Busi/TransOut", req) + .Add(busiUrl + "/busi.Busi/TransIn", req); + + await msg.Prepare(busiUrl + "/busi.Busi/QueryPrepared_404"); + await msg.Submit(); + + var trans = await ITTestHelper.GetTran(gid); + Assert.Equal("succeed", trans.Transaction.Status); + Assert.Equal(30, trans.Transaction.RequestTimeout); + } + + + [Fact] + public async Task SetTimeoutToFail_default() + { + var provider = ITTestHelper.AddDtmHttp(); + var transFactory = provider.GetRequiredService(); + + var gid = "msgTestGid" + Guid.NewGuid().ToString(); + var msg = transFactory.NewMsg(gid); + // msg.SetTimeoutToFail(30); + msg.EnableWaitResult(); + var req = ITTestHelper.GenBusiReq(false, false); + var busiUrl = ITTestHelper.BuisHttpUrl; + msg.Add(busiUrl + "/busi.Busi/TransOut", req) + .Add(busiUrl + "/busi.Busi/TransIn", req); + + await msg.Prepare(busiUrl + "/busi.Busi/QueryPrepared_404"); + await msg.Submit(); + + var trans = await ITTestHelper.GetTran(gid); + Assert.Equal("succeed", trans.Transaction.Status); + Assert.Equal(0, trans.Transaction.RequestTimeout); + } + + [Fact] + public async Task SetTimeoutToFail_30s() + { + var provider = ITTestHelper.AddDtmHttp(); + var transFactory = provider.GetRequiredService(); + + var gid = "msgTestGid" + Guid.NewGuid().ToString(); + var msg = transFactory.NewMsg(gid); + msg.SetTimeoutToFail(30); + msg.EnableWaitResult(); + var req = ITTestHelper.GenBusiReq(false, false); + var busiUrl = ITTestHelper.BuisHttpUrl; + msg.Add(busiUrl + "/busi.Busi/TransOut", req) + .Add(busiUrl + "/busi.Busi/TransIn", req); + + await msg.Prepare(busiUrl + "/busi.Busi/QueryPrepared_404"); + await msg.Submit(); + + var trans = await ITTestHelper.GetTran(gid); + Assert.Equal("succeed", trans.Transaction.Status); + Assert.Equal(30, trans.Transaction.TimeoutToFail); + } } \ No newline at end of file diff --git a/tests/Dtmcli.Tests/MsgTests.cs b/tests/Dtmcli.Tests/MsgTests.cs index c326255..29cfbe7 100644 --- a/tests/Dtmcli.Tests/MsgTests.cs +++ b/tests/Dtmcli.Tests/MsgTests.cs @@ -50,6 +50,7 @@ public async void Submit_Should_Succeed() .EnableWaitResult() .SetRetryInterval(10) .SetTimeoutToFail(100) + .SetRequestTimeout(30) .SetDelay(10) .SetBranchHeaders(new Dictionary { @@ -192,6 +193,43 @@ public async void DoAndSubmitDB_Should_QueryPrepared_When_BusiCall_ThrowExeption dtmClient.Verify(x => x.TransRequestBranch(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); } + [Fact] + public async void SetRequestTimeoutTest() + { + var fakeFactory = new Mock(); + + var mockHttpMessageHandler = new MsgMockHttpMessageHandler(); + var httpClient = new HttpClient(mockHttpMessageHandler); + fakeFactory.Setup(x=>x.CreateClient(It.IsAny())).Returns(httpClient); + + var dtmOptions = new DtmOptions { DtmUrl = "http://localhost:36789" }; + var dtmClient = new DtmClient(fakeFactory.Object, Microsoft.Extensions.Options.Options.Create(dtmOptions)); + + var gid = "TestMsgNormal"; + var msg = new Msg(dtmClient, _branchBarrierFactory, gid); + + var req = new { Amount = 30 }; + + msg.Add(busi + "/TransOut", req) + .Add(busi + "/TransIn", req) + .AddTopic("test-topic", req) + .EnableWaitResult() + .SetRetryInterval(10) + .SetTimeoutToFail(100) + .SetRequestTimeout(30) + .SetDelay(10) + .SetBranchHeaders(new Dictionary + { + { "bh1", "123" }, + { "bh2", "456" }, + }); + + await msg.Prepare(busi + "/query"); + await msg.Submit(); + + Assert.True(true); + } + public class MsgMockHttpMessageHandler : DelegatingHandler { public MsgMockHttpMessageHandler() @@ -209,6 +247,7 @@ protected override async Task SendAsync(HttpRequestMessage Assert.True(transBase.WaitResult); Assert.Equal(10, transBase.RetryInterval); Assert.Equal(100, transBase.TimeoutToFail); + Assert.Equal(30, transBase.RequestTimeout); Assert.Contains("bh1", transBase.BranchHeaders.Keys); Assert.Contains("bh2", transBase.BranchHeaders.Keys); Assert.Equal(3, transBase.Payloads.Count);