使用 NetMQ Dealer 和 Router 模式进行单元测试时出现间歇性超时失败

问题描述 投票:0回答:1

我遇到了一个令人困惑的问题,我使用 NetMQ 库的 xUnit 测试有时会通过,有时会因超时而失败。这种不一致使得查明根本原因变得困难。

场景:我在 NetMQ 中使用经销商和路由器模式。

问题:长时间运行测试时,测试成功。但是,如果我立即重新运行它,它经常会超时。此行为会持续几分钟,然后再次成功运行。 成功运行后,运行netstat显示以下内容:

127.0.0.1:8080         kubernetes:1742        TIME_WAIT

这是有问题的代码的简洁版本:

单元测试:

public class SocketPulseReceiverTest
{
    private readonly ServiceCollection _serviceCollection = new();
    private readonly IServiceProvider _serviceProvider;

    public SocketPulseReceiverTest()
    {
        _serviceCollection.AddSocketPulseReceiver(new List<Assembly> { typeof(TestAction).Assembly });
        _serviceProvider = _serviceCollection.BuildServiceProvider();
    }

    [Fact]
    public void InvalidRequest_ReturnsErrorReply()
    {
        var service = _serviceProvider.GetService<ISocketPulseReceiver>();

        service?.Start("tcp://localhost:8080");
        using var dealer = new DealerSocket("tcp://localhost:8080");
        try
        {
            dealer.SendFrame("invalid data");
            var received = dealer.TryReceiveFrameString(TimeSpan.FromSeconds(2), out var replyStr);
            Assert.True(received, "Did not receive a reply in the expected time");
            var reply = JsonConvert.DeserializeObject<Reply>(replyStr!);
            Assert.Equal(State.Error, reply?.State);
        }
        finally
        {
            service?.Stop();
            dealer.Close();
            NetMQConfig.Cleanup();
        }
    }
}

使用路由器插座的功能:

private void Worker(string address)
{
    using var routerSocket = new RouterSocket();
    routerSocket.Bind(address);

    while (_isRunning)
    {
        var msg = new NetMQMessage();
        try
        {
            routerSocket.TryReceiveMultipartMessage(TimeSpan.FromMilliseconds(100), ref msg, 2);
        }
        catch (NetMQException) { /* NetMQ internal exception handling */ }

        if (msg == null || msg.FrameCount == 0) continue;

        if (msg.FrameCount != 2)
            throw new InvalidOperationException("Unexpected msg received...");

        var identity = msg.Pop().ConvertToString();
        var content = msg.Pop().ConvertToString();

        Reply result;
        try
        {
            result = HandleMessage(content);
        }
        catch (Exception e)
        {
            result = new Reply { State = State.Error, Content = e.ToString() };
        }

        routerSocket.SendMoreFrame(identity).SendFrame(JsonConvert.SerializeObject(result));
    }
}

经过调试,我观察到Router Socket始终接收客户端发送的帧。然而,回复似乎没有到达Dealer Socket。

有人对测试表现不一致的原因以及如何确保结果一致有见解或建议吗?

提前谢谢您!

.net-core networking concurrency xunit.net netmq
1个回答
0
投票

我设法查明并解决了问题。

问题的根本原因在以下行中找到:

var identity = msg.Pop().ConvertToString();

在这一行中,我将字节码标识转换为字符串,然后尝试将该字符串发送回经销商。当然,这会导致经销商无法识别它,特别是如果转换后的字符串包含无效字符或问号。这种不一致解释了为什么测试偶尔会通过——只有当字符串转换偶然保留有效字符而没有任何意外符号时。

为了解决这个问题,我修改了代码如下:

NetMQMessage reply = new();
reply.Append(identity);
reply.Append(JsonConvert.SerializeObject(result));
routerSocket.TrySendMultipartMessage(reply);

这取代了之前的错误:

routerSocket.SendMoreFrame(identity).SendFrame(JsonConvert.SerializeObject(result));

通过保留原始身份格式并使用 Append 方法,我确保身份保持完整,从而允许一致的消息路由回经销商。

虽然这似乎是许多人可能不会遇到的疏忽,但我分享它是希望它可以帮助其他遇到类似情况的人。

© www.soinside.com 2019 - 2024. All rights reserved.