Discord bot editing messages too slow - javascript

I want my discordbot to send send a message with an attached file in it and a text. Then the bot has to edit this text a couple of times but the problem is that when bot eddits message 5 times then it waits some time and then edits again 5 times etc etc. How can i make it edit messages without stopping?
if(msg.content.includes("letter")){
msg.channel.send("alphabet", { files: ["/Users/48602/Videos/discordbot/aaa.png"]})}
if(msg.content === 'alphabet'){
msg.edit("**a**")
msg.edit("**b**")
msg.edit("**c**")
msg.edit("**d**") // Here bot stop for a 2 seconds and i dont know why
msg.edit("**e**")
msg.edit("**f**")
msg.edit("**g**")
msg.edit("**h**")
msg.edit("**i**")
msg.edit("**j**")// Here bot stop for a 2 seconds and i dont know why
msg.edit("**k**")
msg.edit("**l**")
msg.edit("**m**")
msg.edit("**n**")
msg.edit("**o**") // Here bot stop for a 2 seconds and i dont know why
msg.delete()
}

Discord has a rate limit of 5 in each request. Trying to bypass this would be considered API abuse (the solutions later is not API abuse).
Exceeding this limit will pause other requests until a certain number of seconds has passed. Along with my research, I came across this simple explanation:
5 anything per 5 seconds per server (if you did not understand what I said above).
On Discord's Developer guide on rate limits, it tells you this:
There is currently a single exception to the above rule [rate limits] regarding different HTTP methods sharing the same rate limit, and that is for the deletion of messages. Deleting messages falls under a separate, higher rate limit so that bots are able to more quickly delete content from channels (which is useful for moderation bots).
One workaround, without API abusing, would be to send messages, and delete the previous messages since there is a higher limit for deleting messages.
Another workaround would be to add intermediate timeouts to your animation.
A simple method such as:
function async wait = { require("util").promisify(setTimeout); };
//syntax: await wait(1000); to "pause" for 1 second
You will need to play around with the timings so it fits your intended animation speed, and without pausing due to the rate limit.

Related

Handle Multiple Concurent Requests for Express Sever on Same Endpoint API

this question might be duplicated but I am still not getting the answer. I am fairly new to node.js so I might need some help. Many have said that node.js is perfectly free to run incoming requests asynchronously, but the code below shows that if multiple requests hit the same endpoint, say /test3, the callback function will:
Print "test3"
Call setTimeout() to prevent blocking of event loop
Wait for 5 seconds and send a response of "test3" to the client
My question here is if client 1 and client 2 call /test3 endpoint at the same time, and the assumption here is that client 1 hits the endpoint first, client 2 has to wait for client 1 to finish first before entering the event loop.
Can anybody here tells me if it is possible for multiple clients to call a single endpoint and run concurrently, not sequentially, but something like 1 thread per connection kind of analogy.
Of course, if I were to call other endpoint /test1 or /test2 while the code is still executing on /test3, I would still get a response straight from /test2, which is "test2" immediately.
app.get("/test1", (req, res) => {
console.log("test1");
setTimeout(() => res.send("test1"), 5000);
});
app.get("/test2", async (req, res, next) => {
console.log("test2");
res.send("test2");
});
app.get("/test3", (req, res) => {
console.log("test3");
setTimeout(() => res.send("test3"), 5000);
});
For those who have visited, it has got nothing to do with blocking of event loop.
I have found something interesting. The answer to the question can be found here.
When I was using chrome, the requests keep getting blocked after the first request. However, with safari, I was able to hit the endpoint concurrently. For more details look at the following link below.
GET requests from Chrome browser are blocking the API to receive further requests in NODEJS
Run your application in cluster. Lookup Pm2
This question needs more details to be answer and is clearly an opinion-based question. just because it is an strawman argument I will answer it.
first of all we need to define run concurrently, it is ambiguous if we assume the literal meaning in stric theory nothing RUNS CONCURRENTLY
CPUs can only carry out one instruction at a time.
The speed at which the CPU can carry out instructions is called the clock speed. This is controlled by a clock. With every tick of the clock, the CPU fetches and executes one instruction. The clock speed is measured in cycles per second, and 1c/s is known as 1 hertz. This means that a CPU with a clock speed of 2 gigahertz (GHz) can carry out two thousand million (or two billion for those in the US) for the rest of us/world 2000 million cycles per second.
cpu running multiple task "concurrently"
yes you're right now-days computers even cell phones comes with multi core which means the number of tasks running at the same time will depend upon the number of cores, but If you ask any expert such as this Associate Staff Engineer AKA me will tell you that is very very rarely you'll find a server with more than one core. why would you spend 500 USD for a multi core server if you can spawn a hold bunch of ...nano or whatever option available in the free trial... with kubernetes.
Another thing. why would you handle/configurate node to be incharge of the routing let apache and/or nginx to worry about that.
as you mentioned there is one thing call event loop which is a fancy way of naming a Queue Data Structure FIFO
so in other words. no, NO nodejs as well as any other programming language out there will run
but definitly it depends on your infrastructure.

How often can I rename discord channel's name?

This is not a post about HOW to change channel's name (I know it).
I have an international server using several bots. And we all depend on UTC time (to coordinate through the world). So there was borned a solution to make a time-bot which will show current UTC-time in the dedicated channel nobody can visit. And yes, precision is necessary, even seconds.
I created a voice channel with permissions not to join for #everyone. Everything worked fine, it updated every 1000 ms. Then (after several months of good work) something was broke, it started updating incorrect. I've increased update interval up to 5000 ms and it have started to work fine... until yesterday.
Now it doesn't work anymore. Even if I increase interval much more. It works sometimes I don't really know what the interval is, it's huge and unpredictable.. the time-bot is broken for now and cannot be used anymore in that case.
Is there any restrictions for updating channel name? I can't find any information about this in available documentations.
Client.setInterval(() => {
const { h, m, s } = getTime();
channel.edit({ name: `${getClockEmoji({ h, m })} UTC: ${h}-${m}-${s}` }).catch((err) => console.log(err));
}, updateInterval);
Providing data is correct, 'cause I send it to console and it updates as good as I need in interval I set. But channel name not updates that often..
Does discord filter too often update requests?
discord.js version is v.12.2.0
Discord had set the rate limit for things like channelrename to 2 requests per 10 minutes.
"Normal" requests like sendmessage is limited to 10,000 per 10 minutes.
This seems to likely be an issue directly related to rate limiting:
https://discord.com/developers/docs/topics/rate-limits
IP addresses that make too many invalid HTTP requests are automatically and temporarily restricted from accessing the Discord API. Currently, this limit is 10,000 per 10 minutes. An invalid request is one that results in 401, 403, or 429 statuses.
For every API request made, we return optional HTTP response headers containing the rate limit encountered during your request.
You should probably decrease the interval by a considerable amount to reduce the risk of the IP being restricted.

Is setTimeout the right option for scheduling tasks spanning days?

I am creating a user management system. There's an option for moderators to block users for a specific number of days. After receiving a block request, the disabled attribute for the user is set to true in the database. After the specified duration passes, the value is set back to false. The duration may range from 1 - 10 days. Is setTimeout() the right choice? Will it be cpu intensive if run for many users simultaneously?
Here's the function from my program. The complete program uses express as a server and mongoose to interact with the mongodb database.
function disableUser(req,res) {
let username = req.body.username;
let app = req.body.app;
let duration = req.body.duration;
let reason = req.body.reason;
User.find({username:username}).then((result) => {
let user = result[0];
user.disabled = true;
user.save().then((user) => {
disableMail(app, user.email, duration, reason); //send mail to user
// schedule a task to set user.disabled to false after the duration
}, (err) => {
res.status(500).send(err);
});
}, (err) => {
res.status(500).send(err);
});
}
EDIT :
Seeing all the comments and answers, I think I'll implement something like this : store the end date of the ban (calculated using something like momentjs) along with the disabled attribute. A setInterval will run separately and check the date every 12 hours for all the users with disabled set to true. If the end_date matches the current date, the disabled attribute will be set to false.
A setTimeout() set for several days from now will work and it's not hardship on the server (even if you have a lot of them), but it's still probably not the right design choice for the following reasons:
setTimeout() is only good for the duration of your server running. As soon as your server restarts for any reason (crash, planned maintenance, etc...), the setTimeout() is gone so even if you did use a setTimeout() you'd have to use a more durable means of storage anyway so you could restore all the timers on a server restart.
You don't need ms timing. A multi-day ban can be removed hourly or even daily.
My suggestion is that instead of a timer, you run some periodic process that could be run once an hour that does a query to find any banned users whose ban has expired. You will want to store the ban and the ban duration in the database in a way that makes this query efficient (perhaps in a separate table of banned users). Then, you can run this query once an hour, remove the user from the banned table and then re-enable the "disabled" user attribute for those users whose ban has expired.
This type of design should meet all your objectives, is a durable way of storing the ban and can be implemented efficiently.
Using setTimeout is probably impractical for a few reasons. First, you are correct that it would be intensive, especially if you have a lot of blocked users. Second, it wouldn't survive a server restart, which may occur because you are pushing new code.
If you go with some automated background task, then consider:
You probably want to check if the user is blocked on all API calls and form submissions at the server-side. This could be part of your general security/permission checks on write calls.
You'll need some error handling in the UI whenever a banned user's API call is rejected.
You may want some background task that executes like once a minute and checks for blocked users and expires the ban when appropriate. A chron type job, or quartz (if Java), or something similar if on Node, can run the query and perform the updates.

Output multiple responses from a single Intent

I have an Alexa Skill which I want to have an initial response to an intent, then after a delay, states another response.
I've attempted using multiple response.tell(...) call with a setTimeout() between them, but this only responds with the first .tell() and ends. (.tell() is set to end the session, but even if I set this to false, my code still never reaches the setTimeout() )
I have included some psuedo-code about what I would like to do:
intentHandlers.DynamicDurationIntent = function(intent, session, response) {
var calculatedDuration = doCalculation();
var speechDuration = convertToSpeech(calculatedDuration);
var speechOutput = "Your duration will last <say-as interpret-as="time">' +
speechDuration +
'</say-as>";
response.tell(speechOutput); //I get this far
setTimeout(function () {
var speechOutputEnd = "Great job! You're done.";
response.tell(speechOutputEnd);
}, calculatedDuration);
}
An example of this model is used in the 7 Minute Workout Alexa Skill.
Is this feasible using AWS Lambda?
Thanks!
This is not an AWS Lambda related issue, this is an Alexa related issue.
Part of the confusion seems to be the asynchronous nature of node.js making it appear that you could send multiple responses to Alexa, you can't. The way to think about Alexa is in the same request/response type nature that a normal API call would be. Your second response.tell has nowhere to send its data because the original request has long since concluded.
The way to think about it is Alexa is holding a conversation with the user and doesn't provide you a way to interrupt the user without them first interacting. Your first response.tell puts the conversation back in the users hands and you can't say anything until they talk to you again.
All that said, there is a straightforward solution that will probably work for you available in the Alexa platform today.
You can provide a single response with SSML and put breaks in the speech output. The documentation for an SSML break shows that you would look like <break time="420s"/> and you are already using SSML in your response.
However, for usability I would not recommend putting in a 7 minute pause. You have alternatives such as putting in minute pauses and having encouraging speech between each minute (actually you'd want to pause for 50 something seconds probably). Another alternative would be for you to play some time of music or workout related sound for the 7 minutes using the audio SSML tag.

How can I track "online" statuses of users if a server crashes?

I have multiple heroku dynos and a chat app. When a user logs in, their status is set to "online" in MongoDB. However, if a server crashes, their status will still be set as online. How can I update the user status to be "offline" when a server crashes?
If I only had one dyno, this would be easy. I'd just update every user to be "offline" when the server starts. Unfortunately, this is not possible with multiple servers.
As per our chat and comments.
The best option is to go with checking against last activity. So seeing when the last message was sent and if it happened within the last let's say 5 minutes they are online if there were no activity mark them as offline.
Like I mentioned in the comments, if you are not storing a date_created on the messages documents you will not have to change anything because _id stores the timestamp
ObjectId("507f191e810c19729de860ea").getTimestamp()
that returns this Date object
ISODate("2012-10-17T20:46:22Z")
This answer is another option (if you are wanting to keep them as online even if they are not sending messages):
If you would like to know they are still active even when they're not jumping from page to page, include a bit of javascript to ping your server every 60 seconds or so to let you know they are still alive. It'll work the same way as my original suggestion, but it will update your records without requiring them to be frantically browsing your site at least once every five minutes.
var stillAlive = setInterval(function () {
/* XHR back to server
Example uses jQuery */
$.get("stillAlive.php");
}, 60000);

Categories

Resources