How do I make the loop run every 5 seconds and update the queue list?
#tasks.loop(seconds=5.0)
async def queue_check():
channel = client.get_channel(2342354325223424224)
queue = []
for members in channel.members:
queue.append(members.display_name)
queue_check.start()
print(queue)```
Well you need to start it, but not inside the loop itself
#tasks.loop(seconds=5.0)
async def queue_check():
channel = client.get_channel(2342354325223424224)
queue = []
for members in channel.members:
queue.append(members.display_name)
print(queue)
queue_check.start()
You can either start it in the on_ready event, in the global scope or in a command, you can also stop it using queue_check.stop
In the context of a cog, start the loop in the __init__ block, if it's on your main file, you can start it anywhere before bot.run
In any case the method is queue_chech.start()
Related
I am trying to send a REST API call to retrieve a lot of data. Now this data is returned in JSON format and is limited to 2000 records each call. However, if there are more than 2000 records then there is a key called nextRecordsUrl with a link to an endPoint with the next 2000 records.
And this pattern continues until there are less than 2000 records in a single call and then nextRecordsUrl is undefined.
I have this loop that essentially pushes the data to an array and then calls the endpoint listed in the nextRecordsUrl key.
do {
for (var i in arrLeads.records) {
let data = arrLeads.records[i];
let createDate = new GMT(data.CreatedDate, "dd-MM-YYYY");
let fAssocDate = new GMT(data['First_Campaign_assoc_date__c'],"dd-MM-YYYY");
let lAssocDate = new GMT(data['Last_Campaign_assoc_date__c'], "dd-MM-YYYY");
let convDate = new GMT(data.ConvertedDate, "dd-MM-YYYY");
leads.push([data.FirstName, data.LastName, data.Id, data.Email, data.Title, data['hs_contact_id__c'], createDate, data.Company, data.OwnerId, data.Country, data['Region_by_manager__c'], data.Status, data.Industry, data['Reason_for_Disqualifying_Nurture__c'], data['Reason_for_Disqualifying_Dead__c'], data['Lead_Type__c'], data['First_Campaign_Name__c'], data['First_CampaignType__c'], fAssocDate, data['Last_Campaign_Name__c'], lAssocDate, data['Last_Campaign_Type__c'], convDate, data.ConvertedAccountId, data.ConvertedContactId, data.ConvertedOpportunityId]);
}
var arrLeads = getQueryWithFullEndPoint(arrLeads.nextRecordsUrl);
} while (arrLeads.nextRecordsUrl != null && arrLeads.nextRecordsUrl != undefined);
I used to use the regular while loop, but it caused obvious problems in that it wouldn't run at all if the initial call had an empty nextRecordsUrl field.
But this also has an issue. While the first iteration works well, the last one does not because it makes the call on the next iteration before the loop checks the nextRecordsUrl field.
So essentially, it will loop through all the records normally. But when it gets to the last one, it has already run the last endPoint and will break the loop, because now the 'nextRecordsUrl key is empty. So the last iteration will be ignored.
I thought of moving the call to after the check, right after the do {, but that will cause problems for the first iteration.
I also thought about duplicating the for loop after the do, but I prefer a cleaner solution that doesn't involve duplicating code.
So how do I write this code in a way that takes into account the first iteration, even if there no second iteration and the last iteration, where it has records but has an empty nextRecordsUrl, without having to double up the code?
I actually managed to solve this with a small tweak in the code.
My issue is that I getting the next batch before I could test the original, and so I was always 1 batch short.
The solutions was actually to define a variable at the beginning of each loop arrLeadsNext = arrLeads.nextRecordsUrl;
and have the while statement check this variable.
So it looks like this:
do {
var arrLeadsNext = arrLeads.nextRecordsUrl;
for (var i in arrLeads.records) {
let data = arrLeads.records[i];
let createDate = new GMT(data.CreatedDate, "dd-MM-YYYY").process();
let fAssocDate = new GMT(data['First_Campaign_assoc_date__c'], "dd-MM-YYYY").process();
let lAssocDate = new GMT(data['Last_Campaign_assoc_date__c'], "dd-MM-YYYY").process();
let convDate = new GMT(data.ConvertedDate, "dd-MM-YYYY").process();
leads.push([data.FirstName, data.LastName, data.Id, data.Email, data.Title, data['hs_contact_id__c'], createDate, data.Company, data.OwnerId, data.Country, data['Region_by_manager__c'], data.Status, data.Industry, data['Reason_for_Disqualifying_Nurture__c'], data['Reason_for_Disqualifying_Dead__c'], data['Lead_Type__c'], data['First_Campaign_Name__c'], data['First_CampaignType__c'], fAssocDate, data['Last_Campaign_Name__c'], lAssocDate, data['Last_Campaign_Type__c'], convDate, data.ConvertedAccountId, data.ConvertedContactId, data.ConvertedOpportunityId]);
}
var arrLeads = (arrLeadsNext != null) ? getQueryWithFullEndPoint(arrLeadsNext) : '';
} while (arrLeadsNext != null && arrLeadsNext != undefined);
So the check at the end hasn't been changed by the next API call for the next batch as it will only change once the next iteration of the loop begins.
I need a command that shows the list of the commands with cooldowns and the time remaining to use the command again. Is it possible especially putting the command in a cog? If yes, can you help me how to do the command?
It's definitely possible, to get all commands in cooldown and their remaining time. However, discord.py does not give direct access to it, and thus we have to abuse private class variables to get them
Code:
import datetime
#client.command()
async def cooldowns(ctx: commands.Context):
string = ""
for command in client.walk_commands():
dt = ctx.message.edited_at or ctx.message.created_at
current = dt.replace(tzinfo=datetime.timezone.utc).timestamp()
bucket = command._buckets.get_bucket(ctx.message, current)
if not bucket:
continue
retry_after = bucket.update_rate_limit(current)
if retry_after:
string += f"{command.name} - {retry_after} Seconds\n"
else:
string += f"{command.name} - `READY`\n"
string = string or "No commands are on cooldown"
await ctx.send(string)
Here is what the above code will look like for commands not on cooldown:
It will follow:
command 1 - READY
command 2 - READY
...
command n - READY (and so on)
and, here is how it will look if commands are on cooldown:
Explaining how the code works:
string = ""
We initialize an empty string in a string variable, this is the string we will add our lines to and send it all at once.
for command in bot.walk_commands():
dt = ctx.message.edited_at or ctx.message.created_at
current = dt.replace(tzinfo=datetime.timezone.utc).timestamp()
bucket = command._buckets.get_bucket(ctx.message, current)
bot.walk_command() is a method that gives us a generator object, which is essentially a generator of all the command objects the bot has stored (i.e: everything under #bot.command(), #commands.command, and #commands.group)
dt is just storing the current time the message was created at, it's a datetime object
message.created_at is a time naive offset and so we bind a timezon to it with its replace method and then we get a timestamp of that with the timestamp() method of datetime.datetime objects
all of the things we did is a waste, the third line is the meat and potatoes of what we want. command._buckets.get_bucket is an internal, we provide the current message object and the timestamp we created earlier.
This gives us our Cooldown object (The one you create with #commands.cooldown(1, 5, commands.BucketType.user), it basically yields what is inside the ()) [This is None for commands with no cooldowns]
here is what it looks like, just for understanding.
if not bucket:
continue
retry_after = bucket.update_rate_limit(current)
if retry_after:
string += f"{command.name} - {retry_after} Seconds\n"
else:
string += f"{command.name} - `READY`\n"
await ctx.send(string)
if not bucket:
continue
If a bucket is not found, command does not have cooldown, meaning we can skip over it.
retry_after = bucket.update_rate_limit(current)
This basically gets us our remaining time (it's a float)
returns None if it's not on cooldown
if retry_after:
string += f"{command.name} - {retry_after} Seconds\n"
else:
string += f"{command.name} - `READY`\n"
the if statement checks if it returned a float, if yet then command is on cooldown and we add the command name along side the cooldown time
the else is for if it's not on cooldown, then it adds the command name and READY along side it.
And at the end we send the entire string.
In my case, I only have one command that had cooldown, which is spotify.
Creating a command that shows all cooldowns is possible. You can do this with a for loop and the is_on_cooldown() function.
Here is an example of a command to return a list of commands and if they are on cooldown:
#client.command(pass_content=True)
async def cooldowns(ctx):
cooldown_string = ""
for command in client.commands:
if command.is_on_cooldown(ctx):
cooldown_string += f"\n{command} - **Time Left:** {command.get_cooldown_retry_after(ctx)}MS"
await ctx.send(cooldown_string)
From here you can add condition statements to only show commands on cooldown.
I am using a postman to automate apis.
Now I am using following request , lets say :-
{
"customerId": "{{currentClientId}}"
}
Where clientid is a dynamic variable whose value is substituted dynamically as 1 , 2, 3,4 so on..
I call this request multiple times using setNextRequest call in this eg lets say 10.This is being done using a counter variable. I am initialising the counter in my previous request to 0 and using for loop with value as counter as 10 calling the request 10 times.There is no response in body just successful http code 204.
I want to store all these clientids coming in request into an environment Client array variable so I wrote a following pre-request script:-
counter = pm.environment.get("counter");
ClientArray = pm.environment.get("ClientArray");
ClientArray.push(pm.environment.get("currentClientId"));
pm.environment.set("ClientArray",ClientArray);
In Test Script, wrote following code :-
counter = pm.environment.get("counter");
if(counter<=10) {
console.log("hi");
postman.setNextRequest("Request");
counter++;
pm.environment.set("counter",counter);
console.log("Counter",counter);
}
The above scipts is throwing
TypeError | ClientArray.push is not a function.
Could someone please advice how to achieve this.
When you retrieve a value from an environment variable like you're doing:
ClientArray = pm.environment.get("ClientArray");
You're not getting an array, you're getting a string which is why you're getting that error. You need to treat the variable like a string, append the currentClientId much like you do for the counter. Something like:
var currentClientIds = pm.environment.get("ClientArray");
currentClientIds = currentClientIds + "," + currentClientId
When you're done appending i.e. out of your loop simply take the string and convert it to an array:
var currentClientIds = pm.environment.get("ClientArray");
var idsArr = curentClientIds.split(',');
So my problem is that trace within the function does trace the first element of the array, but the trace outside if the function does not. I do declare the array variable outside the function, but the data wont save to the array variabel.
var oppgaveLoader:URLLoader = new URLLoader();
oppgaveLoader.load(new URLRequest("oppgaver.txt"));
var oppgaveNr = 0
//store line of text on an array called oppgaver
var oppgaver:Array = []
var oppg:Array = new Array()
oppgaveLoader.addEventListener(Event.COMPLETE, onLoaded);
function onLoaded(e:Event){
oppgaver = e.target.data.split(/\n/)
trace(oppgaver[0]) //This one traces the frist item in the array
}
trace(oppgaver[0])//This one does not trace the first one in the array
Does anyone know why and/or how to fix it if posible?
The file "oppgaver.txt" is located in the same directory as my .fla file
The file "oppgaver.txt" is laid out like this (the text is in norwegian, but each line is going to be a item in the array):
Hvor gjelder forbudsskilt hvis ikke annet er oppgitt?
Hvordan foretar du best mulig bremsing og unnastyring?
Hvordan bør du normalt plassere bilen på en vanlig 2-felst vei?
It's a synchronicity problem.
the last trace happens immediately after you set up your arrays, but those arrays are still empty.
only when the onLoaded function gets called, asynchronously by the URLLoader, they get populated and you can trace their values.
that event listener basically lets you react to an event that happens in the future at some point.
I am trying to write a Gatling script where I read a starting number from a CSV file and loop through, say 10 times. In each iteration, I want to increment the value of the parameter.
It looks like some Scala or Java math is needed but could not find information on how to do it or how and where to combine Gatling EL with Scala or Java.
Appreciate any help or direction.
var numloop = new java.util.concurrent.atomic.AtomicInteger(0)
val scn = scenario("Scenario Name")
.asLongAs(_=> numloop.getAndIncrement() <3, exitASAP = false){
feed(csv("ids.csv")) //read ${ID} from the file
.exec(http("request")
.get("""http://finance.yahoo.com/q?s=${ID}""")
.headers(headers_1))
.pause(284 milliseconds)
//How to increment ID for the next iteration and pass in the .get method?
}
You copy-pasted this code from Gatling's Google Group but this use case was very specific.
Did you first properly read the documentation regarding loops? What's your use case and how doesn't it fit with basic loops?
Edit: So the question is: how do I get a unique id per loop iteration and per virtual user?
You can compute one for the loop index and a virtual user id. Session already has a unique ID but it's a String UUID, so it's not very convenient for what you want to do.
// first, let's build a Feeder that set an numeric id:
val userIdFeeder = Iterator.from(0).map(i => Map("userId" -> i))
val iterations = 1000
// set this userId to every virtual user
feed(userIdFeeder)
// loop and define the loop index
.repeat(iterations, "index") {
// set an new attribute named "id"
exec{ session =>
val userId = session("userId").as[Int]
val index = session("index").as[Int]
val id = iterations * userId + index
session.set("id", id)
}
// use id attribute, for example with EL ${id}
}
Here is my answer to this:
Problem Statement: I had to repeat the gatling execution for configured set of times, and my step name has to be dynamic.
object UrlVerifier {
val count = new java.util.concurrent.atomic.AtomicInteger(0)
val baseUrl = Params.applicationBaseUrl
val accessUrl = repeat(Params.noOfPagesToBeVisited,"index") {
exec(session=> {
val randomUrls: List[String] = UrlFeeder.getUrlsToBeTested()
session.set("index", count.getAndIncrement).set("pageToTest", randomUrls(session("index").as[Int]))
}
).
exec(http("Accessing Page ${pageToTest}")
.get(baseUrl+"${pageToTest}")
.check(status.is(200))).pause(Params.timeToPauseInSeconds)
}
So basically UrlFeeder give me list of String (urls to be tested) and in the exec, we are using count (AtomicInteger), and using this we are populating a variable named 'index' whose value will start from 0 and will be getAndIncremented in each iteration. This 'index' variable is the one which will be used within repeat() loop as we are specifying the name of counterVariable to be used as 'index'
Hope it helps others as well.