By default Rake will stop at the first exception raised.
There doesn't seem to be a command line equivalent to make -k, is there any way to do it programmaticaly?
Unfortunately there is no --keep-going in rake (and I think that's fine). The only way I can think of is to wrap your Rakefile with begin; rescue; end, but it won't make it "keep going" -- it will simply ensure that your rake's execution return is 0.
begin
# Former Rakefile code goes here
rescue
puts $!.inspect
end
I believe that "keep going" isn't possible since when you raise something you already changed your algorithm's flow -- i.e. don't try to solve your problem by ignoring Exceptions.
Related
I am seeing this pattern in someone else's Rakefile:
begin
sh "..."
rescue
abort
end
What's the author doing here? Why rescue if I'm going to abort anyway? Do I understand correctly that this mutes the potential shell error?
I am new to ruby and rake. As far as I understand, the sh is rake's shorthand for FileUtils.sh() (ref). And FileUtils.sh() may raise a RuntimeError (ref).
Does this mean that we are effectively throwing away the information/message in the RuntimeError and exiting rake with an error status, but without a specific error message? Is this a rake/ruby pattern? Any recommended reading?
I want to avoid an error, if a require is not successfull.
I can do it with:
begin
require 'unexisting_script'
rescue LoadError
end
I tried to do the same with a one-line condition:
require 'unexisting_script' rescue LoadError
and get the error no such file to load -- unexisting_script (LoadError)
With other exceptions/commands I have no problem with a one line rescue, this works:
1 / 0 rescue ZeroDivisionError
I also tried to bracket the command, but withous success:
(require 'unexisting_script') rescue LoadError
I can put everything in one line with ;:
begin require 'unexisting_script'; rescue LoadError; end
but I'm still wondering, why the shortest version does not work.
I found some related questions, but none of them is mentioning a problem with require and rescue:
Why does this rescue syntax work?
How does one use rescue in Ruby without the begin and end block
My question:
Can I use rescue in a one-line condition with require? If yes: how? If no: Why?
You cannot specify the error class when you use rescue in postfix/oneliner notation. What rescue LoadError or rescue ZeroDivisionError means is that it will rescue a (subclass of) StandardError, and in such case, evaluate LoadError or ZeroDivisionError, which has no effect. Since ZeroDivisionError is a subclass of StandardError, it was captured, but LoadError is not, and it was not captured.
By the way, I cannot think of a use case where you want to not raise an error when a required file does not exist. Required files are dependencies, and if requiring them fails, then the program will not work correctly anyway. I feel a code smell in what you are doing. When failure of loading a file does not mess the program, that is usually when you should be using load instead of require.
I'd like to know how to programmatically exit a Sinatra application from within the application itself. (There's another SO thread about stopping it from outside the app.)
I want to use Sinatra as a means of receiving control and configuration commands while my application does something unrelated to the Sinatra stuff. I'd like one of the control commands to be 'exit'. Ruby's 'exit' method just seems to result in Sinatra recovering and resuming. I found this in base.rb that I think confirms this:
at_exit { Application.run! if $!.nil? && Application.run? }
So far, the only way I've found is to call Ruby's exit! method, but that bypasses exit hooks and is not a very clean solution.
Is there no way to programmatically tell Sinatra to stop?
I used the following code:
# Exit 'correctly'
get '/exit' do
# /exit causes:
# 15:20:24 web.1 | Damn!
# 15:20:24 web.1 | exited with code 1
Process.kill('TERM', Process.pid)
end
# Just terminate
get '/fail' do
Process.kill('KILL', Process.pid)
end
Take a look at at_exit in config.ru it works for TERM signal:
at_exit do
puts 'Damn!'
exit false
end
Full example is here.
Cheers.
That sort of goes against the grain of Sinatra, but this is just Ruby so you can easily do this via open classes/monkey patching.
Just re-open the base.rb at_exit method and override the Application.run! behavior.
Why not just raise an exception? That will mean that $! is not nil, so the at_exit handler won't restart Sinatra.
An easy way is just to run fail or raise. You can also pass a message, such as fail "Exiting due to x".
Sinatra::Base::quit! or its alias ::stop! is what you are looking for:
require 'sinatra'
get '/quit' do
self.class.quit!
end
get '/stop' do
self.class.stop!
end
Right now if I run my test suite using rake spec I get an error:
1) SegmentsController GET 'index' should work
Failure/Error: get 'index'
undefined method `locale' for #
# ./spec/controllers/segments_controller_spec.rb:14:
in `block (3 levels) in '
This is normal as I do have an error :)
The problem is that the trace isn't very helpful. I know it broke in segments_controller_spec.rb, line 14, but this is just where I call the test:
### segments_controller_spec.rb:14
get 'index'
I would prefer to have the actual line breaking and the complete trace, not the part in the spec folder.
Running with --trace doesn't help.
You must run rspec with -b option to see full backtraces
Another (easier) alternative is to edit the .rspec file, and add the backtrace option.
It should look somewhat like this:
--colour
--backtrace
That will give you the full backtrace.
Hope this helps.
This will also work:
# rails_helper.rb
RSpec.configure do |config|
config.full_backtrace = true
end
Another approach is to clear all backtrace exclusion patterns in spec_helper.rb. I like this solution most as I'm able to keep all RSpec settings in one place and get rid of .rspec file or explicit --backtrace in .travis.yml.
# spec_helper.rb
RSpec.configure do |config|
config.backtrace_exclusion_patterns = []
end
I don't know how to get the controller error to show up in rspec. Sometimes it shows up but I don't know what conditions cause it to show up. Here is a way to see the error fairly quickly though:
Open another terminal session and run:
tail -f log/test.log
Then go back to the terminal session and run just the spec that had the error:
bin/rspec -b spec/requests/posts/index_spec.rb
Go back to the tail of the log and you should see the error, hopefully without too much other stuff surrounding it (because you ran the failing test by itself).
One more option when all else fails is to just add a rescue block and print out the stack try or add a binding pry statement there and use show-stack.
rescue Exception => e
puts ""
puts e.backtrace
puts ""
I have a process that runs on cron every five minutes. Usually, it takes only a few seconds to run, but sometimes it takes several minutes. I want to ensure that only one version of this is running at a time.
I tried an obvious way...
File.open("/tmp/indexer_lock.tmp",'w') do |f|
exit unless f.flock(File::LOCK_EX)
end
...but it's not testing to see if it can get the lock, it's blocking until the lock is released.
Any idea what I'm missing? I'd rather not hack something using ps, but that's an alternative.
I know this is old, but for anyone interested, there's a non-blocking constant that you can pass to flock so that it returns instead of blocking.
File.new("/tmp/foo.lock").flock( File::LOCK_NB | File::LOCK_EX )
Update for slhck
flock will return true if this process received the lock, false otherwise. So to ensure just one process is running at a time you just want to try to get the lock, and exit if you weren't able to. It's as simple as putting an exit unless in front of the line of code I have above:
exit unless File.new("/tmp/foo.lock").flock( File::LOCK_NB | File::LOCK_EX )
Depending on your needs, this should work just fine and doesn't require creating another file anywhere.
exit unless DATA.flock(File::LOCK_NB | File::LOCK_EX)
# your script here
__END__
DO NOT REMOVE: required for the DATA object above.
Although this isn't directly answering your question, if I were you I'd probably write a daemon script (you could use http://daemons.rubyforge.org/)
You could have your indexer (assuming its indexer.rb) be run through a wrapper script named script/index for example:
require 'rubygems'
require 'daemons'
Daemons.run('indexer.rb')
And your indexer can do almost the same thing, except you specify a sleep interval
loop do
# code executing your indexing
sleep INDEXING_INTERVAL
end
This is how job processors in tandem with a queue server usually function.
You could create and delete a temporary file and check for existence of this file.
Please check the answer to this question :
one instance shell script
There's a lockfile gem for exactly this situation. I've used it before and it's dead simple.
If your using cron it might be easier to do something like this in the shell script that cron calls:
#!/usr/local/bin/bash
#
if ps -C $PROGRAM_NAME &> /dev/null ; then
: #Program is already running.. appropriate action can be performed here (kill it?)
else
#Program is not running.. launch it.
$PROGRAM_NAME
fi
Here's a one-liner that should work at the top of any Ruby script:
exit unless File.new(__FILE__)).tap {|f| f.autoclose = false}.flock(File::LOCK_NB | File::LOCK_EX)
There are two issues with the original code.
First, the reason it's blocking is that the call to #flock is missing File::LOCK_NB:
Don't block when locking. May be combined
with other lock options using logical or.
Second, if a File object is closed (whether at the end of an #open block as in the code above, via explicit #close, or implicitly auto-closed when the File is garbage-collected), the underlying file descriptor is closed and the lock is released. To prevent this you can set #autoclose =false.
Ok, working off notes from #shodanex's pointer, here's what I have. I rubied it up a little bit (though I don't know of a touch analogue in Ruby).
tmp_file = File.expand_path(File.dirname(__FILE__)) + "/indexer.lock"
if File.exists?(tmp_file)
puts "quitting"
exit
else
`touch #{tmp_file}`
end
.. do stuff ..
File.delete(tmp_file)
Can you not add File::LOCK_NB to your lock, to make it non-blocking (i.e. it fails if it can't get the lock)
That would work in C, Perl etc.
At a higher level, you might find the lock_method gem useful:
def the_method_my_cron_job_calls
# something really expensive
end
lock_method :the_method_my_cron_job_calls
It uses lockfiles stored on the local filesystem (what was being discussed above) by default, but you can also configure remote lock storage:
LockMethod.config.storage = Redis.new([...]) # a remote RedisToGo instance, perhaps?
Also...
def the_method_my_cron_job_calls
# something really expensive
end
lock_method :the_method_my_cron_job_calls, (60*60) # automatically expire lock after an hour