How to create rate limits for webhook messages

I want to send messages to a webhook but in the case that there is an abundant amount of requests per minute, I want to be able to rate limit it aka make a message queue. However, trying datastores seemed tricky and MessagingService especially tricky. I have to acknowledge if every server is shut down and that the queue will go down by 1 if there is any value every 2 seconds.

Here’s an example of what I mean by the queue going down:

local datastore = game:GetService("DataStoreService"):GetDataStore("QueueStore")
-- obviously the problem is i wouldn't want to run this in every server possible
while true do
    local success, result = pcall(function()
        return datastore:GetAsync("Queue")
    end)
    if success then
        datastore:UpdateAsync("Queue", function(previous)
            if not previous then previous = {} return previous end
            if #previous == 0 then return end
            previous[#previous] = nil
            return previous
        end
    end
    wait(2)
end

What’s a good way to handle this?

2 Likes

So you want to send messages to a webhook to acknowledge if every server is shut down or am I reading this incorrectly. I do not think DataStore is the particular best way to do this. If all possible I would definitely recommend messaging service.

Add a debounce function. For example:

local debounce = false
function call(...)
  if debounce == true then repeat wait() until debounce == false end

  debounce = true
  -- Function goes here

 delay(Wait_time, function()
   debounce = false
 end)
end

No, I mean a queue where an array’s contents are shifted down by 1 every 2 seconds (if there are contents). Refer to the edited post for what I mean.

@Trizxistan I’m not aiming for a debounce, it’s a rate limit. The purpose is to prevent a certain number of requests being sent per minute. For example, I would want my rate limit to be 25 msgs per minute allowed. So If the queue goes up to 25 entries, further messages wouldn’t be sent. Keep in mind that any server can send a request so I have to account for requests beyond one server.

1 Like

Okay, so what have you tried with MessagingService? I do strongly recommend that over DataStores as it is a feature ROBLOX implemented for that very purpose. While datastores in theory can work without a problem I would prefer MessagingService over DataStores any day.

I have tried it. The problem is when I want to get the length of the queue that it was tricky to get the length since you can’t do a :Wait() on SubscribeAsync while getting the message you want. I even tried hooking a bindable event for it to fire when it got the message but it ended in an infinite yield. I tried to make one server control all of the queue work as well.

I don’t have the code since I tried to do a datastore approach now which could work but I have to address the fact that all servers may shut down and entries could remain in the datastore.

Making a rate limit:

In this code, we’re doing the rate limit 20 changes per second.

local rate_limit = 20
local wait_time_to_reset = 60
local current_rates = 0

function addtempRate()
-- This will add a temporary Rate and remove it after the duration
 current_rates = current_rates + 1

 delay(wait_time_to_reset, function()
   current_rates = current_rates - 1
 end)
end

function create(...)
  if current_rates == rate_limit then return end

  addTempRate()
  -- Functions goes here
end
1 Like

How about having one server control the time in between the time reset OR you could mix DataStore with messaging Service. For example

Maybe DataStore tick() as your last tick and if the current tick() is greater than 60 then reset and send a message.

A time to reset is actually a good idea. Maybe I can implement in the datastore a variable that represents the time it was updated and if I check the current time and compare it and it still has many values left, I can reset it. What do you think I should use as that supplementation to the datastore, tick()?

@serverOptimist seemed we had nearly the same idea at the same time.

2 Likes

Ha, it actually crossed my mind when I was typing midway.

It crossed my mind before he was talking about a time to reset actually at all but I decided to remark about it.

I highly recommend using tick or os.time to track time to reset. However, os.time works well in real time.

No need to use os.time as os.time tracks as stated, os and the time elapsed in UTC(Or local if desired but we wouldn’t do that), tick() tracks a timestamp. You could use it but for the sake of this I’d suggest just tick()+waitInterval

Alright thanks guys I’m going to test it out and come back with a result and marked solution.

Seems like there’s a way better way to handle rate limiting and that RequestAsync of HttpService can solve it. I can receive header info based on rate limit from Discord requests, here is info on that.

I am quite basic at HttpService so I won’t know what to do from here since I just use PostAsync frequently for webhooks.

Hoping someone who is good at HttpService could help me. :slightly_smiling_face:

2 Likes