question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Message Queue to prevent weird behavior

See original GitHub issue

Hey there,

my bot currently has 2 commands. /warn <IUser> <string> and /unwarn <IUser> <string>. While it’s no problem if only one person can warn and unwarn members, it got complicated after I gave those rights to a second person.

Scenario:

User A will be warned by myself and another moderator. If this happens at the same time, I don’t havve anything in my code to queue these commands and make them execute one after another. They both get executed at the same time. Thus User A will get Warning 3 for my command execution and again Warning 3 for the moderators command execution.

So far I’ve tried it with SimpleSemaphore but with this approach I only get the following message in my log: A MessageReceived handler is blocking the gateway task.

Is there a built in Message queue?

If not, is there a need for in this project? Because I really need it and would create a Pull request if finished.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

6reactions
DaNeubicommented, Mar 14, 2020

I’ve come up with a solution.

There is a class called StaticLock

using System;
using System.Threading.Tasks;

namespace sahnee_bot.Util
{
    public static class StaticLock
    {
        //Variables

        /// <summary>
        /// Command warn
        /// </summary>
        private static bool _lockCommandWarning = false;
        private static readonly Object _lockObjectCommandWarning = new object();
        
        

        #region Getter

        /// <summary>
        /// Tries to lock the warn command
        /// </summary>
        /// <returns></returns>
        private static bool TryLockCommandWarning()
        {
            lock (_lockObjectCommandWarning)
            {
                if (_lockCommandWarning == false)
                {
                    _lockCommandWarning = true;
                    return _lockCommandWarning;
                }
                return false;                
            }
        }

        #endregion

        #region Setter

        /// <summary>
        /// Unlocks the warn command
        /// </summary>
        /// <returns></returns>
        public static bool UnlockCommandWarning()
        {
            lock (_lockObjectCommandWarning)
            {
                if (_lockCommandWarning)
                {
                    _lockCommandWarning = false;
                    return true;
                }
                if (_lockCommandWarning == false)
                {
                    return true;
                }
                return false;
            }
        }
        

        #endregion

        #region LockAquiration

        /// <summary>
        /// Locks the warn command if possible
        /// otherwise it will wait
        /// </summary>
        /// <param name="delay"></param>
        /// <returns></returns>
        public static async Task AquireWarningAsync(int delay = 100)
        {
            while (!TryLockCommandWarning())
            {
                await Task.Delay(delay);
            }
        }

        #endregion
    }
}

To use you make it the following in your command:

        [Command("warn")]
        [RoleHandling(RoleTypes.WarningBotAdmin)]
        [Summary("Warns a specific user in his current guild")]
        public async Task WarnAsync([Summary("The user that will be warned")]IUser user
            , [Summary("The reason why the user had been warned")]string reason)
            {
                try
                {
                    await StaticLock.AquireWarningAsync();
                    await this.ExecuteWarnAsync(user, reason); //Thats where I packed my logic for the command
                }
                finally
                {
                    StaticLock.UnlockCommandWarning();
                }
            }
5reactions
ZargorNETcommented, Mar 13, 2020

Run it in a new Task.Run() and then use a lock. This should fix it 🤔

Read more comments on GitHub >

github_iconTop Results From Across the Web

You Probably Don't Need a Message Queue
Message Queues are systems that let you have fault-tolerant, distributed, decoupled, etc, etc. architecture. That sounds good on paper. Message ...
Read more >
The Big Little Guide to Message Queues
If a queue becomes too large then we get the idea that messages are not being consumed fast enough (in near-real-time). In this...
Read more >
php - RabbitMQ weird behavior on dead letter queue for ...
1 Answer 1 ... Dead letter exchanges (DLXs) are normal exchanges. If your message is unroutable (due to the routing key, for instance)...
Read more >
What are Benefits of Message Queues?
Understand the benefits of message queues, including better performance, increased reliability, granular scalability, and simplified decoupling.
Read more >
RabbitMQ Durable Queue: A Comprehensive Guide 101
RabbitMQ is a free and open-source message broker and queueing software that ... Queues have characteristics that define their behavior.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found