I am working with a database via IRB, and I would like to make periodic changes in the database (e.g., every 10 sec) showing the log in STDOUT.
Also, I would like to have manual control being able to change the database and to stop the first process.
So far I came up to the following
def start
stop
#running = Thread.new do
loop do
fork do
puts 'change the database'
end
sleep 10
end
end
nil
end
def stop
#running.kill if #running
end
However, this is not running every 10 sec unless I enter something in the main IRB thread.
How to make it working?
Some versions of readline on OSX are blocking. If one experiences the behavior you described, they can disable readline by putting
IRB.conf[:USE_READLINE] = false
in .irbrc
Works fine for me (tested in irb with ruby 1.9.2-p180 and 1.8.7-p334).
Related
This is my code snippet
def execution_start
puts "About to start"
system("appium")
puts "Done!!"
end
When executing this I see the output About to start, and appium server is launched. But after that, I do not see anything happening. It's stuck forever. Any idea?
system blocks until the command it runs has completed. To run a command and return immediately, use Process#spawn:
def execution_start
puts "About to start"
pid = Process.spawn("appium")
puts "Done!!"
end
You can then use the returned PID to monitor whether the process has finished executing, and with what exit code, later in your program.
(Note that, per the documentation, you need to Process#wait the PID eventually, or at least register disinterest using Process#detach to prevent the subprocess from becoming a zombie.)
So I'm trying to have my ruby (no rails) application be run with a single call from the terminal i.e. 'ruby run.rb'. However I have two scripts that need to be run, app.rb and app2.rb, the issue is, both these scripts don't finish - they keep on being run so as to keep the system running, this means that one of the scripts never gets run - it calls the first script (app.rb) and never the second (app2.rb) these scripts need to be run concurrently!
It does work when I open another command line and just run one script in each however.
I have tried:
def runApp
system("ruby app.rb")
end
def runApp2
system("ruby app2.rb")
end
t1 = Thread.new{runApp()}
t2 = Thread.new{runApp2()}
t1.join
t2.join
However this will only run the first thread (the one running app.rb) because this is being constantly run. Any ideas how it can also run the second thread concurrently?
:EDIT: One of the scripts is using the Sinatra gem, the other also calls one of its functions every ten seconds.
So one possible solution I've found is
system("ruby app.rb & ruby app2.rb")
This only works however if running from linux I think however so I would still appreciate any further solutions.
According to the documentation you can do it like this:
threads = []
threads << Thread.new{runApp()}
threads << Thread.new{runApp2()}
threads.each { |thr| thr.join }
I guess this works because each is parallel.
I was just thinking about how great it would be to be able to run a program and then hit a keystroke to invoke pry and debug. Maybe there is a gem out there that injects binding.pry dynamically during runtime that I don't know about. If there isn't, how would you make a keystroke that inserts binding.pry before the next line of ruby script that is about to execute?
Assuming a POSIX OS, you could try adding a signal handler in your ruby program. The ruby documentation even gives an example of your use case:
.. your process may trap the USR1 signal and use it to toggle debugging (http://www.ruby-doc.org/core-2.1.3/Signal.html)
Signal.trap('USR1') do
binding.pry
end
Then, to send the signal:
kill -s SIGUSR1 [pid]
Edit: A more complete example: application.rb
My naïve suggestion above will fail with a ThreadError: current thread not owner. Here's a better example using a global $debug flag.
#!/usr/bin/env ruby
require 'pry'
$debug = false
Signal.trap('USR1') do
puts 'trapped USR1'
$debug = true
end
class Application
def run
while true
print '.'
sleep 5
binding.pry if $debug
end
end
end
Application.new.run
This seems to work best when application.rb is running in the foreground in one shell, and you send the SIGUSR1 signal from a separate shell.
Tested in Mac OS 10.9.5. YMMV.
While writing a ruby script on Windows (ruby -v outputs ruby 1.9.3p545) I encountered an interesting and rather specific problem. I was attempting to close an opened file if a user terminates execution. For example,
begin
f = File.open("monkeys.txt", "w+")
#stuff with the file
rescue Exception => e #I know this is a bad idea
puts e.backtrace
ensure
f.close
end
Now, this works if I terminate execution via Ctrl+C while running this in cmd. However, when I hit the "X" on the cmd prompt window, the code in the ensure block doesn't run. I tried something like...
at_exit do
f.close if !f.closed?
end
...but that still doesn't execute the code I want it to when the X button is hit.
So, what do I do in order to force "ensure" code in Ruby if it's closed via that X button?
Well, I don't really program for windows, so I might get lost on the details, but let me try to shed some light with this workaround for Linux:
#ppid = Process.ppid
pid = fork do
loop do
sleep(1)
begin
Process.getsid(#ppid)
rescue Errno::ESRCH
File.new("process_down.txt", "a+")
exit(1)
end
end
end
Process.detach(pid)
puts "Process detached"
What this does is it creates a forked process, detaches it from the main process and keeps listening for when the main process is killed (it'll throw Errno::ESRCH on Process.getsid if the #ppid is no longer there), so it'll create a .txt file and exit. I don't know how to handle forking and pids in windows, but that's just to try and show you some possibilities =]
I have an application running with Flask, and use Compass as css preprocessor. Which means I need to start the python server and compass for development. I made what I thought was a clever Rakefile to start everything from one command and have everything run in only one terminal window.
Everything works, but the problem is when I try to stop everything (with cmd + c), it only kills the compass task and the Flask server keeps running. How can I make sure every tasks are stopped? Or is there an alternative to simultaneously launch several tasks without this issue?
Here is my rakefile, pretty simple:
# start compass
task :compass do
system "compass watch"
end
# start the flask server
task :python do
system "./server.py"
end
# open the browser once everything is ready
task :open do
`open "http://127.0.0.1:5000"`
end
# the command I run: `$ rake server`
multitask :server => ['compass', 'python', 'open']
EDIT
For the record, I was using a Makefile and everything worked perfectly. But I changed part of my workflow and started using a Rakefile, so I Rakefile'd everything and got rid of the Makefile for simplicity.
That is because system creates new processes for your commands. To make sure they are killed alongside your ruby process, you will need to kill them yourself. For this you need to know their process ids, which system does not provide, but spawn does. Then you can wait for them to exit, or kill the sub-processes when you hit ^C.
An example:
pids = []
task :foo do
pids << spawn("sleep 3; echo foo")
end
task :bar do
pids << spawn("sleep 3; echo bar")
end
desc "run"
multitask :run => [:foo, :bar] do
begin
puts "run"
pids.each { |pid| Process.waitpid(pid) }
rescue
pids.each { |pid| Process.kill("TERM", pid) }
exit
end
end
If you do a rake run on that, the commands get executed, but when you abort, the tasks are sent the TERM signal. There's still an exception that makes it to the top level, but I guess for a Rakefile that is not meant to be published that does not matter too much. Waiting for the processes is necessary or the ruby process will finish before the others and the pids are lost (or have to be dug out of ps).