How do I output the % complete of resque-status? - ruby

I'm using resque-status for Resque/Redis...
https://github.com/quirkey/resque-status
I basically want to create a new Sinatra method .. something like below. I only have 2 JobsWithStatus so it could either return both or a specific one, i dont really care.
post '/getstatus' do
# return status here of all kinds (or specific)
end
Then I want to output the % complete via jquery on the frontend using a polling timer that checks the status every 5 seconds.
This is what I have
post '/refresh' do
job_id = PostSaver.create(:length => Forum.count)
status = Resque::Status.get(job_id)
redirect '/'
end
It says in the documentation i can just use status.pct_complete but it always returns 0? Even then, I'm new to ruby and even IF the variable showed the proper % complete, I'm not sure how to make that variable work inside of a separate sinatra entry (in /getstatus rather than /refresh).
I tried this however and it keeps returning 0
post '/refresh' do
job_id = PostSaver.create(:length => Forum.count)
status = Resque::Status.get(job_id)
sleep 20
status.pct_complete.to_s
end

Saw your question over on reddit…
To have the status come back as something other than 0, you need to use the at (http://rubydoc.info/github/quirkey/resque-status/master/Resque/JobWithStatus:at) method to set a percentage during the calculation you're running.
You probably don't want sleep calls inside an action. The timer should be in jQuery.
Sharing Status
post '/refresh' do
job_id = PostSaver.create(:length => Forum.count)
status = Resque::Status.get(job_id)
sleep 20
"{'percent_complete':#{status.pct_complete},'job_id':'#{job_id}'}"
end
Then in whatever is getting the status (some jQuery#ajax call?), you can grab the job_id from the returned JSON and then with your next request, you might do something like:
post '/status' do
status = Resque::Status.get(params['job_id'])
"{'percent_complete':#{status.pct_complete}}"
end

Related

In JMeter, How do i loop until a result is found

I have a request in Jmeter that I need to loop until I find the result I am looking for. I have read a few bits about a while controller but found them unhelpful as they seem to glance over vital information or are using an older version of Jmeter
I'm currently using Jmeter 5.0, and I have attempted to implement a while controller but failed as I think I do not understand how to properly handle the response, or even grab it, and then use it as a comparison to assert if the item exists.
I get a response from the HTTP request call response that looks a little somthing like this:
{"data":{"getIDs":{"Page": 1,"PageSize": 25,"PageCount": 1,"isFirstPage": true,"batches":[{"id":"b601a257-13fe-4de3-b779-a5922e89765a"},{"id":"b601a257-13fe-4de3-b779-a5922e89765b"},{"id":"b601a257-13fe-4de3-b779-a5922e89765c"}]}}
I need to recall the endpoint until I have found the ID I am looking for or cancel after 10 attempts
So after a bit of fumbling around I, I figured on my own answer that seems to work well. But I would suggest looking at other sources before taking mine as gospel.
The basic structure looks as follows:
Within a thread I set the variables then create the while loop as the next step. Within the While loop I created a counter then added the request I wanted to loop after. To make the loop work for me, I have three items sat under the request.
A Response Assertion: this check for a 200 status as the call should never fail
A Constant Timer: There is a delay between polls of the end point
A JSR223 Assertion: groovy code used ensure the while loop logic is handled
User Defined Variables:
Here i have setup two variables:
DONE: Done is a string value I alter if my JSR223 Assertion finds the values I'm looking for in the HTTP request
MyValue (this is dynamically driven in my actual test, for demo purpose, I’m just declaring a value to look for i.e. 12345)
While Controller:
I still feel i may not understand this correctly, however after some googling I came across the following code that works for me despite some errors in the JMeter console:
${__javaScript(("${DONE}" != "yep" && ${Counter} < 10),)}
This code is saying that the while loop will continue until either of these two conditions are met:
DONE, the variable created earlier, is equal to the value yep
Counter is less than 10 (Counter is declared beneath the while loop)
Counter:
this was a simple configuration step that just worked once I understood it needed to be within the while loop, i configured the following:
Starting value = 1
Increment = 1
Exported Variable Name = Counter
Ticked 'Track Counter independently for each user'
Ticked 'Reset counter on each thread group iteration'
(Exported Variable Name: you can call this whatever you want, I’ve named it counter for the purpose of this demo)
JSR223 Assertion:
This is a simple script assertion that just uses a Boolean and a couple of if statements to assert the state of the test.
import org.apache.commons.lang3.StringUtils;
def done = vars.get("DONE");
String response = prev.getResponseDataAsString(); //retrieves the http request response as text
String MyValue = vars.get("MyValue");
def counter = vars.get("Counter");
//Find Substring within response string and stor result as boolean
String container = response;
String content = MyValue;
boolean containerContainsContent = StringUtils.containsIgnoreCase(container, content);
//Check if the true condition is met and change the value so the loop exits
if (containerContainsContent == true){
log.info("------------------------Got Here");
vars.put("DONE", "yep");
}
//Force test to fail after 10 loops
if (Counter.toString() == "10"){
assert 1 == 2
}

Using JobQueue to continuously refresh a message

I'm building a Telegram bot that uses ConversationHandler to prompt the user for a few parameters and settings about how the bot should behave. This information is stored in some global variables since it needs to be available and editable by different functions inside the program. Every global variable is a dictionary in which each user is associated with its own value. Here's an example:
language = {123456: 'English', 789012: 'Italian'}
where 123456 and 789012 are user ids obtained from update.message.from_user.id inside each function.
After all the required information has been received and stored, the bot should send a message containing a text fetched from a web page; the text on the web page is constantly refreshed, so I want the message to be edited every 60 seconds and updated with the new text, until the user sends the command /stop.
The first solution that came to my mind in order to achieve this was something like
info_message = bot.sendMessage(update.message.chat_id, text = "This message will be updated...")
...
def update_message(bot, update):
while True:
url = "http://example.com/etc/" + language[update.message.from_user.id]
result = requests.get(url).content
bot.editMessageText(result, chat_id = update.message.chat_id, message_id = info_message.message_id)
time.sleep(60)
Of course that wouldn't work at all, and it is a really bad idea. I found out that the JobQueue extension would be what I need. However, there is something I can't figure out.
With JobQueue I would have to set up a callback function for my job. In my case, the function would be
def update_message(bot, job):
url = "http://example.com/etc/" + language[update.message.from_user.id]
result = requests.get(url).content
bot.editMessageText(result, chat_id = update.message.chat_id, message_id = info_message.message_id)
and it would be called every 60 seconds. However this wouldn't work either. Indeed, the update parameter is needed inside the function in order to fetch the page according to the user settings and to send the message to the correct chat_id. I'd need to pass that parameter to the function along with bot, job, but that doesn't seem to be possible.
Otherwise I would have to make update a global variable, but I thought there must be a better solution. Any thoughts? Thanks.
I had the same issue. A little digging into the docs revealed that you can pass job objects a context parameter which can then be accessed by the callback function as job.context.
context (Optional[object]) – Additional data needed for the callback function. Can be accessed through job.context in the callback. Defaults to None
global language
language = {123456: 'English', 789012: 'Italian'}
j=updater.job_queue
context={"chat_id":456754, "from_user_id":123456, "message_id":111213}
update_job = job(update_message, 60, repeat=True, context=context)
j.put(update_job, next_t=0.0)
def update_message(bot, job):
global language
context=job.context
url = "http://example.com/etc/" + language[context["from_user_id"]]
result = requests.get(url).content
bot.editMessageText(result,
chat_id = context["chat_id"],
message_id = context["message_id"])

Getting Large Twitter User Lists (And Retrying)

I'm trying to get the list of follower user IDs for a certain handle. Something like
client = Twitter::REST::Client.new(...)
client.follower_ids(handle).each { |id| puts id }
But for a handle with thousands of followers I get Twitter::Error:TooManyRequests. I considered trying
client = Twitter::REST::Client.new(...)
begin
client.follower_ids(handle).each { |id| puts id }
rescue Twitter::Error::TooManyRequests => error
sleep error.rate_limit.reset_in
retry
end
But won't that restart the each loop from the beginning every time I get TooManyRequests (and thus never finish)?
I am using the twitter gem v5.8.0.
The gem repo was recently updated with an example of how to do this properly.
The key is to put only the loop inside the block.
client = Twitter::REST::Client.new(...)
follower_ids = client.follower_ids(handle)
begin
follower_ids.each { |id| puts id }
rescue Twitter::Error::TooManyRequests => error
sleep error.rate_limit.reset_in
retry
end
Warning:
My example is no good!
This code works because the cursor caches the results of each request, so that each time it retries, it doesn't need to request everything from the start. However it does loop through everything already cached before making another request.
This code will output IDs multiple times, whenever a retry occurs. If you write code like this, you need to include something that prevents duplication of loop iterations.

Why Is This Ruby While Statement Not Working

Background: This is using page-object, and Rspec. The page, objects are setup correctly. Basically what is happening is its skipping the while statement and going directly to checking of the variable label exists on the page.
What it SHOULD do is check if the label variable is on the page and if not then wait 20 seconds and refresh the page then check again for up to 30 times and if it fails on the 30th time then it should fail all together. If it finds it then it should check again and pass it.
def check_label(label, current_page)
labels_filter_element.click
check_label_sla(label, current_page)
current_page.text.should include label
end
def check_label_sla(label, current_page)
t = 30
i = 0
while i < t
if current_page.text.should include label
return
else
sleep(20)
current_page.refresh
i += 1
end
end
end
I think what is happening is if current_page.text.should include label is always returning TRUE, but I'm not sure. If more info is needed please let me know.
I am making the following assumptions:
The behaviour you are seeing is that the page is first loaded, the labels_filter_element is clicked, the label is not on the page and the test fails immediately without refreshing the page.
label is a string
Given these assumptions, the problem is with the if-statement:
if current_page.text.should include label
When the if statement is executed, it will assert that the page includes the label:
If the page has the label, the code in the if will be executed (ie it will immediately return and the assertion in check_label will pass).
In the case that the page does not have the label, the assertion will throw an exception causing the test to fail immediately (ie the else code will not get executed). So the test is failing inside the check_label_sla method, not at the end of the check_label method (which makes it seem like the while loop is not working).
You want the if statement to check that the text is included, without making an assertion. Therefore you want:
if current_page.text.include? label
So your check_label_sla method would become:
def check_label_sla(label, current_page)
t = 30
i = 0
while i < t
if current_page.text.include? label
return
else
sleep(20)
current_page.refresh
i += 1
end
end
end
Or you could reduce it to:
def check_label_sla(label, current_page)
30.times do
return if current_page.text.include? label
sleep(20)
current_page.refresh
end
end

Ruby: Twitter API: Get All followers

Anyone have any idea why the next cursor isn't changing in the below code?
cursor = "-1"
followerIds = []
while cursor != 0 do
followers = Twitter.follower_ids("IDTOLOOKUP",{"cursor"=>cursor})
cursor = followers.next_cursor
followerIds+= followers.ids
sleep(2)
end
After the first iteration where cursor = -1, it gets assigned the nextcursor from the twitter api. However, when this is sent to the twitter API on subsequent iterations, I get the same response back as I did the first time.. with the same next_cursor.
Any ideas what I'm doing wrong? I'm using the twitter gem.
Edit: [Suggestion regarding being rate limited removed]
The problem is the cursor option to follow_ids. It should read:
followers = Twitter.follower_ids("IDTOLOOKUP",{:cursor=>cursor})
Note the use of symbol, not string. In the original code, the "cursor" option being provided was being ignored and follower_ids was doing the default behavior, namely returning the first page of followers.

Resources