setTimeout(() => {
targets.forEach(target => target.roles.remove(arole));
message.channel.send(`Removed ${arole}`);
}, RoleTime);
}
}
I use the above snippet to take away the roles of mentioned users after mentioned time. It works perfectly (I use ms to store RoleTime in milis). But when the time is like 12h the bot doesn't seem to reply and take away the role(Hosted on Heroku). Any idea why? What are the other ways to achieve this?
setTimeout doesn't work for long periods of time on services like heroku, and in general it's a bad idea to use setTimeout for operations like this anyway.
Some are saying to use a cron job for something like this, but due to the nature of the discord gateway, this is probably not a good idea.
Consider storing the expiry jobs in some sort of persistent database (sql, mongo etc)
Within your bot, every set period of time (30 seconds, 60 minutes) etc:
Query the database, fetch all expiry jobs that have passed or are equal to the expiry time
SELECT profile_snowflake,role_snowflake FROM expiry_jobs WHERE expiry_time <= ?
Iterate through each expiry job and remove the roles
Reschedule task
This allows for the bot to do expiry jobs across different processes - with services such as heroku, the bot can randomly restart which would completely reset the state of the bot, so you need to use some sort of persistent data store for the expiry jobs.
Related
Hi there and thanks for reading this.
I'm learning how to work with Dialogflow and Firebase Realtime Database and I like these platforms a lot.
I created a very simple DB structure on Firebase with 7 fields and in my agent I query them with a very simple fulfillment.
It seems to be working but every "first query" that I do the next day seems to last about 5000ms so the DB doesn't respond: starting from the second query it works almost in real time so it seems to be sleeping or something.
In my today test at the first query I read this in the Dialogflow log: "webhook_latency_ms": 4663 but at least it worked, generally it doesn't.
It seems like there's some uncertainty about getting data from the DB.
Any suggestion would be very appreciated.
The realtime database structure is this:
serviceAccount
bitstream: "pluto"
cloud: "paperino"
data center: "gastone"
datacenter: "gastone"
ull: "bandabassotti"
vula: "minnie"
wlr: "pippo"
and this is how I query Firebase:
const servizi = agent.parameters.elencoServiziEntity;
return admin.database().ref("serviceAccount").once("value").then((snapshot) =>
{
var accountName = snapshot.child(`${servizi}`).val();
agent.add(`L'Account Manager del Servizio ${servizi} si chiama: ${accountName}`);
console.log(`${servizi}`);
});
The webhook latency isn't always related to the database call - it includes the time that may be required to start the webhook itself. If you're using Firebase Cloud Functions or the Dialogflow Built-In Code Editor (which uses Google Cloud Functions), there is a "cold start" time required to start the function. If your webhook is running somewhere else, on AWS Lambda for example, you may have network latency in addition to the cold start time.
There is very little you can do about this. If you're running with one of Google's Cloud Function solutions, make sure you're running them in the Central-1 region, which is close to where Dialogflow also runs. To avoid the cold start completely - run a server.
Usually, however, the latency and cold start time shouldn't be that long. Which suggests that your code is also taking a while to run. You may wish to look at your logs to see why execution time is taking so long - the call to the Firebase RTDB may be part of it, but there may be other things causing a slowdown that you don't show in your code.
One thing you are doing in your call to Firebase is pulling in the entire record, instead of just pulling in the one field that the user is asking for. This does require more data to be marshaled, which takes more time. (Is it taking a lot more time? Probably not. But milliseconds count.)
If you just need the one field from the record the user has asked for, you can get a reference to the child itself and then do the query on this reference. It might look like this:
const servizi = agent.parameters.elencoServiziEntity;
return admin.database()
.ref("serviceAccount")
.child(servizi)
.once("value")
.then((snapshot) => {
const accountName = snapshot.val();
agent.add(`L'Account Manager del Servizio ${servizi} si chiama: ${accountName}`);
console.log(`${servizi}`);
});
I'm using firebase real-time database.
I'm trying to limit users to allow them post only after minimum of 15 minutes from their latest post (this is to prevent posts looking like chat).
How would I achieve this?
What I've tried is, including timestamp for every post and calculate the time difference from the current time if user tries to post a new one. This would work, but if the user deletes the previous post, then the user would be able to post again right away. So I need a different approach.
What algorithm could I implement?
Thank you Merry Christmas!
The way I would do it is like this. Require the client app to make a multi-location update, writing both the post and the timestamp. The timestamp would be stored per-user, as well as in the post. You could write a security rule on the node containing the posts that checks all of the the following must be true in order for the write to succeed:
The per-user timestamp was only specified with ServerValue.TIMESTAMP
The per-user timestamp is at least 15 minutes later than the existing value (or, if not existing, skip this check)
The post's own timestamp was also specified to have the same value
You can create a new field to store the post from user
User {
. . . ,
PostHistory{
Post1: [timestamp],
Post2: [timestamp]
. . .
},
}
And then every time user create a new post you can check with the postHistory.
I am trying to implement notifications that do not need the interaction of the backend to be shown. The use of this is to put a remind me button, that would send a notification on certain time of the day (that the user specified). I am pretty new to service workers but I understand that they work asynchronously. That being said, is there any way in which I could do something like the following pseudocode?
function timeLeft(time){
setTimeout(() => showNotification(), time);
}
This would work if I put it on a regular javascript file and the user has the browser still open.
It does not need to be exactly like that, it just needs to solve my problem. Thank you un advance.
First you need to have an ID for each browser. If you use the Push API, then you can use the browser endpoint.
When a user adds a reminder, you must store the tuple (endpoint, send_at, reminder) in your database on your server
Run a cron job on your server (or create a scheduled job with Sidekiq, etc.) in order to send the reminder at the correct time (using the Push API)
Otherwise you can use a service which allows you to create scheduled notifications: see this example on my blog.
I have a bot with a command that allows the user to input a message separated with a dash and then a specified time, this is then passed to the bot and the bot reminds the user with the message after the specified amount of time has passed.
function reminder(msg) {
const message = msg.content.replace(this.prefix+this.name+" ","");
const params = message.split("-");
setTimeout(() => {
msg.channel.sendMessage(params[0]);
}, (parseInt(params[1])*1000));
}
I intend to run this bot on Heroku, but since I'm just a teenager and this is a hobby for me I have to use the free dyno hours that Heroku gives me every month. If someone uses this function of the bot will the timing mechanism of setTimeout keep my dynos enabled and use the free dyno hours?
Edit: If you believe there is a better free alternative to Heroku that any of you know of that would be great :)
Yes and no.
Let's assume the logic in setTimeout will be running after every less than 30 minutes, so YES the heroku server will be still awake, so it'll be using the free dyno hours.
But if the message to be sent after more than 30 minutes, let's say one hour, so if there is no any requests hitting your server in this period , your server will sleep after 30m of inactivity, so NO as long as no incoming requests.
Read more about Heroku free dyno hours, here.
You can try this: http://neversleep.ml
It watches your server and will send notification emails if it crashes.
I have a mean.js server running that will allow a user to check their profile. I want to have a setInterval like process running every second, which based on a condition, retrieve data from another server and update the mongoDB (simple-polling / long-polling). This updates the values that the user sees as well.
Q : Is this event loop allowed on nodejs, if so, where does the logic go that would start the interval when the server starts? or can events only be caused by actions (eg, the user clicking their profile to view the data).
Q: What are the implications of having both ends reading and writing to the same DB? Will the collisions just overwrite each other or fault. Is there info on how much read/write would overload it?
I think you can safely do a mongoDB cronjob to update every x day/hour/minutes. In the case of user profile, I assume thats not a critical data which require you to update your DB in real time.
If you need to update in real time, then do a DB replication. Then you point it to a new DB thats replicated on a real time.