想要从应用程序批处理消息并作为块发送



我正在桌面Windows应用程序上汇总一些简单的检测,我想将有关应用程序中(可能在不同的线程上(发生的事情的消息写入列表或队列,然后定期(按时间或消息数(将它们打包为json消息并转发到服务器。 虽然我可以简单地设置一个计时器,并在每次触发时发送消息组,但必须有一种基于某种设计模式的更简洁的方法。 寻找如何以优雅的方式处理这个问题。 似乎这可能是观察者模式...

我正在寻找简单的东西,不想设置消息队列软件或类似的东西,只是将它们打包并发送到 Web 服务。 谢谢!

如果你想编写自己的代码,你可以将一个列表包装在一个类中,当有足够的消息要发送时,该类处理发送消息。

使用下面的类,您只需创建它的全局实例,然后您的线程就可以调用

Application.MessageQueue.AddMessage($"{timestamp} - {threadName}: Some message");

这只是我的头顶,但该类的简化版本看起来像这样:

class MessageQueue
{
    public int MaxQueueSize
    {
        get { return maxQueueSize; }
        set
        {
            lock (lockObject)
            {
                // Setting this to < 1 means messages will not be sent automatically
                // (the calling application must call 'SendMessages' itself)
                if (value < 1) value = int.MaxValue;
                maxQueueSize = value;
            }
        }
    }
    private int maxQueueSize;
    private List<string> unsentMessages;
    private readonly object lockObject = new object();
    public MessageQueue(int maxQueueSize)
    {
        MaxQueueSize = maxQueueSize;
        unsentMessages = new List<string>();
    }
    public void AddMessage(string message)
    {
        lock (lockObject)
        {
            unsentMessages.Add(message);
        }
        if (unsentMessages.Count >= MaxQueueSize)
        {
            SendMessages();                
        }
    }
    public void SendMessages()
    {
        lock (lockObject)
        {
            var messagesToSend = new List<string>();
            while (unsentMessages.Any())
            {
                // Send messages in batches no larger than 'MaxQueueSize'.
                // This allows for dynamic changing of MaxQueueSize, so
                // if it changes from Int.Max to 10, we don't try to send
                // Int.Max messages to the remote server all at once
                messagesToSend = unsentMessages.Take(MaxQueueSize).ToList();
                unsentMessages = unsentMessages.Skip(MaxQueueSize).ToList();
                // Code to send messages to server goes here:
                // RemoteApplication.WebApi.LogMessages(messagesToSend);
                Console.WriteLine($"Message Batch (max {MaxQueueSize} messages):");
                Console.WriteLine($" - {string.Join($"{Environment.NewLine} - ", messagesToSend)}");                    
            }
        }
    }
}

如果它有帮助,这是我用来测试它的简单程序:

private static void Main()
{
    // Start message queue with setting to NOT send any messages
    var messageQueue = new MessageQueue(0);
    var cancel = false;
    // First thread sends a message once per second
    var t1 = new Thread(() =>
    {
        var counter = 1;
        while (true)
        {
            Thread.Sleep(TimeSpan.FromSeconds(1));
            messageQueue.AddMessage($"{DateTime.Now} - First Thread: message #{counter++}");
            if (cancel) break;
        }
    });
    // Second thread sends a message once every 2 seconds
    var t2 = new Thread(() =>
    {
        var counter = 1;
        while (true)
        {
            Thread.Sleep(TimeSpan.FromSeconds(2));
            messageQueue.AddMessage($"{DateTime.Now} - Second Thread: message #{counter++}");
            if (cancel) break;
        }
    });
    t1.Start();
    t2.Start();
    int secondsToWait = 10;
    Console.WriteLine($"nLetting message queue build for {secondsToWait} seconds...");
    // A little progress bar while we're waiting...
    Console.Write(new string((char)9617, secondsToWait));
    Console.SetCursorPosition(0, Console.CursorTop);
    while (secondsToWait > 0)
    {
        secondsToWait--;
        Thread.Sleep(TimeSpan.FromSeconds(1));
        Console.Write((char)9619);
    }
    Console.WriteLine();
    // Set queue size down to 5
    messageQueue.MaxQueueSize = 5;
    // Cancel when user presses any key
    Console.ReadKey();
    cancel = true;
}

请考虑聚合器模式。

您可以根据组中的时间或消息数量定义发送消息组的触发器(以避免流量高时消息繁重(。

最新更新