My initialization failed randomly.
What the better way to implement the init ?
#client = Mongo::Client.new([ cfg["HOST"] ], :database => cfg["NAME"])
At least retry 10 times.
I found some solution like that
begin
coll.insert( { "counter" => i, "named" => "name#{i}" })
rescue Mongo::ConnectionFailure => ex
sleep(0.5)
coll.insert( { "counter" => i, "named" => "name#{i}" })
end
Is there any elegant way to do so ? because I need to do similar init in my project many places
You could extract your connection logic to another method and do
connections = 0
while connections < 10 # or however many
begin
try_connecting
break # only called when no error raised
rescue Mongo::ConnectionFailure => ex
connections += 1
sleep(0.5)
end
end
or maybe this:
def connect
try_connecting
rescue Mongo::ConnectionFailure => ex
fail = true
sleep(0.5)
ensure
return defined?(fail)
end
10.times { break unless connect }
Related
I have a program that uses a method for verification, if that verification failed I would like to return to the method it was called from, for example:
def obtain_pokemon_name
print 'Enter Pokemon: '
pokemon = gets.chomp.capitalize
obtain_basic_attack(pokemon)
end
def obtain_basic_attack(poke)
print 'Enter basic attack: '
basic_attack = gets.chomp.downcase
check_attacks(poke, basic_attack)
obtain_spec_attack(poke)
end
def obtain_spec_attack(poke)
print 'Enter special attack: '
spec_attack = gets.chomp.downcase
check_attacks(poke, spec_attack)
end
def check_attacks(pokemon, attack)
if POKEMON_ATTACKS[pokemon][attack] == nil
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
return # to where this function was called
else
attack
end
end
begin
obtain_pokemon_name
rescue => e
puts "Failed with error code: #{e}"
end
When this is run:
Enter Pokemon: arbok
Enter basic attack: eat
eat is not one of Arbok's attacks, try again..
Enter special attack: test
test is not one of Arbok's attacks, try again..
Attack list:
POKEMON_ATTACKS = {
'Bulbasaur' => {'tackle' => 10.9, 'vine whip' => 15.4, 'power whip' => 21.4, 'seed bomb' => 12.5, 'sludge bomb' => 19.2},
'Ivysaur' => {'razor leaf' => 10.3, 'vine whip' => 15.4, 'power whip' => 21.4, 'sludge bomb' => 19.2, 'solar beam' => 13.3},
'Kakuna' => {'bug bite' => 13.3, 'poison sting' => 10.3, 'struggle' => 8.8},
'Beedrill' => {'bug bite' => 13.3, 'poison jab' => 14.3, 'aerial ace' => 8.6, 'sludge bomb' => 19.2, 'x-scissor' => 14.3},
'Pidgey' => {'quick attack' => 7.5, 'tackle' => 10.9, 'aerial ace' => 8.6, 'air cutter' => 7.6, 'twister' => 5.6},
'Ekans' => {'acid' => 9.5, 'poison sting' => 10.3, 'gunk shot' => 20.0, 'sludge bomb' => 19.2, 'wrap' => 3.8},
'Arbok' => {'acid' => 9.5, 'bite' => 12.0, 'dark pulse' => 12.9, 'gunk shot' => 20.0, 'sludge wave' => 17.6},
}
So my question is, if the attack is not present in the data, how can I return back to the calling method? So for instance if I call arbok and his attack is tackle if it doesn't exist in the hash, how would I return to the obtain_basic_attack(poke) method?
RIght here:
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
return # to where this function was called
you should call the original method again. i.e.
if POKEMON_ATTACKS[pokemon][attack] == nil
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
return obtain_spec_attack(poke)
You could alternatively add this logic to obtain_spec_attack:
def obtain_spec_attack(poke)
loop do
print 'Enter special attack: '
spec_attack = gets.chomp.downcase
attack_found = check_attacks(poke, spec_attack)
if attack_found
break attack_found # this will return attack_found from the loop
else
puts "attack not found"
end
end
end
edit
looking at your question again, I realize you want to return to a method multiple levels up. You could use the approaches I've already outlined, or alternatively use rescue:
def obtain_basic_attack(poke)
begin
print 'Enter basic attack: '
basic_attack = gets.chomp.downcase
check_attacks(poke, basic_attack)
obtain_spec_attack(poke)
rescue AttackNotFoundError
retry # runs the 'begin' block again
end
end
def obtain_spec_attack(poke)
print 'Enter special attack: '
spec_attack = gets.chomp.downcase
check_attacks(poke, spec_attack)
end
def check_attacks(pokemon, attack)
if POKEMON_ATTACKS[pokemon][attack] == nil
puts "#{attack} is not one of #{pokemon}'s attacks, try again.."
raise AttackNotFoundError
else
attack
end
end
In order to use a custom error like AttackNotFoundError, you need to define the error class somewhere:
class AttackNotFoundError < StandardError; end
You could use any error really, such as raise StandardError, but it's better to restrict what errors you're rescuing so that you don't accidentally rescue an unrelated error.
How to handle Mogo replica set Mongo::ConnectionFailure exception in Ruby ?
Tried:
begin
$mongo = Mongo::MongoReplicaSetClient.new(['seed1:27017', 'seed2:27017', 'seed3:27017'], :read => :primary, :rs_name => 'rs0', :connect_timeout => 30, :op_timeout => 30)
mongo = $mongo.db('db_name')
rescue Exception => ex
puts ex.message
rescue Mongo::ConnectionFailure => ex
puts ex.message
rescue RuntimeError => ex
puts ex.message
rescue => ex
puts ex.message
end
No one can handle exception message of rescue block
solved with:
def rescue_mongo_failures(max_retries=60)
retries = 0
begin
yield
rescue Mongo::ConnectionFailure => ex
retries += 1
# here you can get ex.message
raise ex if retries > max_retries
retry
end
end
def rescue_mongo_failures do
$mongo = Mongo::MongoReplicaSetClient.new(['seed1:27017', 'seed2:27017', 'seed3:27017'], :read => :primary, :rs_name => 'rs0', :connect_timeout => 30, :op_timeout => 30)
mongo = $mongo.db('db_name')
$mongo.db.stats
end
I have a script that runs perfectly in the ChromeWebDriver but fails on PhantomJS. When I check if an element exists i get the following error:
[ERROR - 2014-01-07T19:31:55.878Z] WebElementLocator - _handleLocateCommand - El
ement(s) NOT Found: GAVE UP. Search Stop Time: 1389123115867
This doesn't really seem like an issue as the script continues. However, later on the script will fail unable to locate the following element:
question.div(:class => "choices")
This particular script visits a page that has test questions on it. They are in random order. The script decided what kind of question it is and chooses a random answer.
Thanks for any help. Here is the relevant code:
def QuestionType(question)
if question.div(:class => "questionPrompt").text_field.exists?
puts "FITB"
FITB(question)
#elsif question.div(:class => "choices").ul(:class =>"choices-list").li(:index => 1).checkbox.exists?
elsif question.checkbox.exists?
puts "Checkbox"
Checkbox(question)
else
puts "Radio"
Radio(question)
end
end
def FITB(question)
arn = Random.new.rand(0..10)
if arn == 0
answers.li(:index => arn).radio.set
else
idx = 0
begin
question.div(:class => "questionPrompt").text_field(:index => idx).set("Test #{idx}")
idx = idx + 1;
end while question.div(:class => "questionPrompt").text_field(:index => idx).exists?
end
puts "FITB Complete"
end
def Checkbox(question)
allAnswers = question.div(:class => "choices")
answers = allAnswers.ul
max = answers.lis.length - 1
arn = Random.new.rand(0..max)
if arn == 0
answers.li(:index => arn).radio.set
else
for i in 1..arn
answers.li(:index => i).checkbox.set
end
end
puts "Checkbox Complete"
end
def Radio(question)
allAnswers = question.div(:class => "choices")
answers = allAnswers.ul
max = answers.lis.length - 1
arn = Random.new.rand(0..max)
answers.li(:index => arn).radio.set
puts "Radio Complete"
end
post '/payment/transactions/amount' do # => creates a new charge
content_type :json, :charset => 'utf-8'
class Transaction
def initialize(endUserId, code, referenceCode, callback=false)
#endUserId = endUserId
#code = code
#referenceCode = referenceCode
$callback = callback
$transId = rand(1000)
end
def transId
return $transId
end
def callback
return $callback
end
def postCallback
sleep(5)
RestClient.post"#{$callback}", :message => 'CALLBACK SUCCESS', :content_type => :json
end
def to_json(*a)
{"amountTransaction" => {
"endUserId" => #endUserId,
"paymentAmount" =>{
"chargingInformation" => {"code" => #code, "description" => #description},
"totalAmountCharged"=> "0"
},
"referenceCode" => #referenceCode,
"serverReferenceCode" =>"#{(0...6).map{65.+(rand(25)).chr}.join}", # just an example, can be any string
"resourceURL" => "http://localhost:4567/payment/#{#endUserId}/transactions/amount/#{Trans.transId}",
"transactionOperationStatus" => "Processing"
}}.to_json(*a)
end
end
Trans = Transaction.new(params[:endUserId],params[:code], params[:referenceCode], params[:callback])
jsonTrans = Trans.to_json
receipts.addReceipt(Trans.transId,jsonTrans)
jsonTrans
# fire callback
if Trans.callback then
sleep(10)
Trans.postCallback
end
end
Problem for me is the code following #fire callback. If I omit this if...then , the jsonTrans JSON object is returned as expected. When I include the if...then to fire the callback, then the desired Trans.postcallback occurs after 5 seconds - but the preceding jsonTrans is not returned, it is simply ignored. Any ideas on what I'm doing wrong? To confirm, the desired behaviour is to return the jsonTrans in the HTTP response and then call the postCallback method after 5 seconds (assuming the if evaluates to true). Cheers!
EDIT: Solved by spawning a new thread:
Thread.new{
if Trans.callback then
sleep(5)
Trans.postCallback
end}
jsonTrans
The last statement is what the method returns(outputs) so it ignores your jsonTrans in the output.
The first idea I have would be to reorder it:
#...
Trans = Transaction.new(params[:endUserId],params[:code], params[:referenceCode], params[:callback])
jsonTrans = Trans.to_json
receipts.addReceipt(Trans.transId,jsonTrans)
# fire callback
if Trans.callback then
sleep(10)
Trans.postCallback
end
jsonTrans
end
This should work if you don't expect any output from that RestClient.post-call.
Thanks for the suggestion daddz - actually I managed to solve it by wrapping by spawning a new thread: Thread.new{
if Trans.callback then
sleep(5)
Trans.postCallback
end}
jsonTrans
I have a working TCP/IP socket server that loads 3-flash files in succession. How can I unload previous files and eliminate the garbage build up?
2-Flash clients are active, 1-the loader, 2-the next Flash file being loaded, however "the Flash files don't unload." Maybe there's a "put - kill" method or something similar to addChild removeChild in as3. Any resource would help, since I'm not very familiar with Ruby.
Files involved
POLICY SERVER "server lets Flash files play"
policyserver_little.rb
RUBY TCP/IP SOCKET SERVER "server plays loader, that loads 3-Flash files"
server_little#.rb
FLASH LOADER "client"
loader_little.swf
FLASH MOVIES "numbers_odom.swf, numbers_fruits.swf, $mil.swf"
"msg1, msg2, msg3"
WHAT I SEE
def worker==>end
There's no method to unload.
RUBY SERVER server_little#.rb
require 'socket'
require 'rexml/document'
include Socket::Constants
def create_xml_msg(msg, parent)
el = nil
msg.each do |key, value|
if parent
el = parent.add_element(key)
else
el = REXML::Element.new(key)
end
if value.instance_of?(Hash)
create_xml_msg(value, el)
else
el.text = value.to_s
end
end
return el
end
def worker(client, client_sockaddr, worker_number)
$tid << Thread.new([client, client_sockaddr, worker_number]) do |cl|
Thread.current[:number] = cl[2]
puts("\nThread #{cl[2]} servicing #{Socket.unpack_sockaddr_in(cl[1]).join(':')}")
#2
seq_no = cl[2] * 10000000
loop do
begin
msg1 = {"msg" => {"head" => {"type" => "frctl", "seq_no" => seq_no, "version" => 1.0},
"body" => {"file" => "numbers_odom.swf", "start" => 5,
"end" => 3000, "rate" => 40, "duration" => 60}}}
msg2 = {"msg" => {"head" => {"type" => "frctl", "seq_no" => seq_no, "version" => 1.0},
"body" => {"file" => "numbers_fruits.swf", "start" => 5, "end" => 3000, "rate" => 40, "duration" => 60}}}
msg3 = {"msg" => {"head" => {"type" => "frctl", "seq_no" => seq_no, "version" => 1.0},
"body" => {"file" => "$mil.swf", "start" => 5,
"end" => 3000, "rate" => 40, "duration" => 60}}}
[ msg1, msg2, msg3 ].each do |m|
seq_no += 1
m["msg"]["head"]["seq_no"] = seq_no
xml_msg = create_xml_msg(m, nil)
xml_msg.write(cl[0], 0)
cl[0].putc 0
sleep 10
end
rescue
cl[0].close
puts "\nThread #{Thread.current[:number]} exiting..."
Thread.exit
end
end
end
end
$tid = [] # array of active worker thread ids
$wno = [] # array of active worker numbers
$worker_count = 0
$max_workers = 3
$wlist = Array(1..$max_workers) #array of all possible worker numbers
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 1999, '0.0.0.0' )
begin
socket.bind( sockaddr )
socket.listen( 5 )
rescue
print $!.class, " ", $!
sleep 3
retry
end
loop do
begin
$tid.each do |t|
if (t.status == false || t.status == "aborting" )
t.join
$wno.delete(t[:number])
$tid.delete(t)
$worker_count -= 1
puts("\nWorker count #{$worker_count}")
end
end
client, client_sockaddr = socket.accept_nonblock
if (client)
if ($worker_count >= $max_workers)
puts "\n too many clients...\n"
client.puts("<msg>error: too many clients; closing connection...</msg>")
client.close
else
$worker_count += 1
$wlist.each do |w| #find a hole in worker number list
if (!$wno.include?(w))
$wno << w #add new worker number to the active worker num array
worker(client, client_sockaddr, w)
break
end
end
puts("\nWorker count #{$worker_count}")
end
end
rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EINTR, Errno::EWOULDBLOCK
IO.select([socket], nil, nil, 1)
retry
end
end
REFERENCE
Ruby version 186-25
http://rubylearning.com/satishtalim/ruby_threads.html
A very good resource for socket programming in ruby:
Ruby Sockets: IBM
It was tough for me to get a feel for your code by reading through it, so I can't give you a direct answer. However I can tell you that if you want a good resource for sockets in ruby that pdf is it.
In general i think the only way to eliminate garbage is to fork off a process, let it do the garbage-y stuff then die. If that's your question. NB that jruby, macruby, and rubinius have more advanced GC's.
-r