stop start database - ruby-on-rails

I am developing Rails v2.3 app. and using MySQL v5.1 .
I need to stop and start mysql database in one of my rake task, but I am not sure how to implement this thing, could some one help me?
namespace :db do
task :some_db_task => :environment do
#shut down mysql
...
#start mysql
end
end
By the way, I am developing on Ubuntu machine.
----------------------- update ----------------------------
I tried exec "/etc/init.d/mysql stop" , I got the following error message:
Rather than invoking init scripts through /etc/init.d, use the service(8)
utility, e.g. service mysql stop
Since the script you are attempting to invoke has been converted to an
Upstart job, you may also use the stop(8) utility, e.g. stop mysql
stop: Rejected send message, 1 matched rules; type="method_call", sender=":1.78" (uid=1000 pid=6331 comm="stop) interface="com.ubuntu.Upstart0_6.Job" member="Stop" error name="(unset)" requested_reply=0 destination="com.ubuntu.Upstart" (uid=0 pid=1 comm="/sbin/init"))
I tried /etc/init.d/mysql stop also on command line, the same error raise,
By following the error message's instruction, I then tried service mysql stop , I got a new error message:
stop: Rejected send message, 1 matched rules; type="method_call", sender=":1.79" (uid=1000 pid=6343 comm="stop) interface="com.ubuntu.Upstart0_6.Job" member="Stop" error name="(unset)" requested_reply=0 destination="com.ubuntu.Upstart" (uid=0 pid=1 comm="/sbin/init"))
why I can not stop mysql??
--------------- update 2 -------------------------
I realize that even though the above mentioned error message shows, the sudo /etc/init.d/mysql stop actually done its job. The MySQL get stopped by this command, meanwhile the message raising.

I'd prefer using system("sudo /etc/init.d/mysqld stop") so you can be sure the database has stoped. system() waits for the command to be executed while exec starts a background thread.
#update you may need "sudo service mysql stop" if you are using ubuntu lucid or newer

Perhaps something like the following?
namespace :db do
task :start do
exec "sudo /etc/init.d/mysqld start"
end
task :stop do
exec "sudo /etc/init.d/mysqld stop"
end
end

you can execute shell command in ruby using exec method as below
exec "/etc/rc.d/init.d/mysqld start" #start mySql
exec "/etc/rc.d/init.d/mysqld stop" #stop mySql

Related

Start NodeJs when starting Rails Server

I have a Rails-App which includes a nodejs server. Is it possible to start and stop the nodejs server when I start/stop the rails server?
I want to put rails s in my terminal and both server should start. By pressing ctrl + c both server should stop.
That sounds like a good candidate for a Rake task, something like (not tested):
# Rakefile
desc "Start Node and Rails servers"
task :start_servers do
`node myapp.js`
`rails s`
end
(And you can specify options as at the command line, for example to run on different ports, etc.)
Use rake start_servers to run the task.
OK, I found a solution. Put this line in an initializer:
system "node ./nodejs/nodejs-server.js &"

Proper deployment of a Rails app with Mina and Foreman

For production purposes I need three processes running. This is my procfile and I use Foreman to start them:
web: bundle exec rails s Puma -p $PORT
queuing: bundle exec clockwork clock.rb
workers: bundle exec rake resque:workers
For deployment I'm using Mina. What's the appropriate way to start Foreman at the end of deploy task? Currently I'm starting like this:
desc "Deploys the current version to the server."
task :deploy => :environment do
deploy do
invoke :'git:clone'
invoke :'deploy:link_shared_paths'
invoke :'bundle:install'
invoke :'rails:db_migrate'
invoke :'rails:assets_precompile'
to :launch do
queue "touch #{deploy_to}/tmp/restart.txt"
queue "bundle exec foreman start"
end
end
end
... but I don't think that's the proper way since the "mina deploy" command never successfully exits and the local console just starts outputting whatever these processes are doing.
Question number two: How do I initialize logging for each of these three processes separately in separate files?
And how do I prevent killing all of these three processes when one of them crashes? How do I make the process restart when it crashes?
Thanks!
OK, so that's 3 questions.
1) I think you want to detach foreman process from the terminal. That way the deployment process will finish and foreman process will be running even after you have disconnected from the server. nohup is great for that, e.g. this will launch your app and pipe all logs to server.log file:
nohup foreman start > server.log 2>&1 &
2) AFAIK, foreman doesn't let you do that. You should probably use another process management service (e.g. systemd, upstart). Thankfully, foreman lets you easily export your config to different process management formats (http://ddollar.github.io/foreman/#EXPORTING).
3) Again, you probably want to separate your processes and manage them separately via upstart, systemd, etc.

Rails Delayed Job production not picking up change in class/job code

I am running a stack of nginx, passenger, rails, delayed_job gem which is running an import.rake task from lib/tasks/ on Ubuntu LTS.
If I make a code change on production to import.rake.
I do a
RAILS_ENV=production script/delayed_job stop
touch tmp/restart.txt
ps aux | egrep '(PID|nginx)'
sudo kill -HUP [PID]
RAILS_ENV=production script/delayed_job start
However, it still does not recognize my change of import.rake. I'm at a loss of what to do. Maybe there is something i'm not thinking of?
I've ran
ps -ef | grep delayed_job
to see if there are any lingering jobs and after running the delayed_job stop command from above all i see is
[server_name] 9426 6168 0 18:46 pts/0 00:00:00 grep --color=auto delayed_job
which shouldn't be an issue. I've also tried just rebooting the server which didn't help.
Any ideas?
Delayed job serializes the instance of your code when it enqueues it, so redeployment won't help unless you change the code that is invoked by your rake task, rather than the rake task itself.
To solve this, decouple the code you change between redeployments from the code that is invoked via delayed job. So, instead of MyLogic.delay.do_stuff, you could do this:
class DelayedTask
def self.do_stuff
self.new.delay.execute
end
private
def execute
MyLogic.do_stuff
end
end
Then just call DelayedTask.do_stuff from your code, and you can change MyLogic.do_stuff in any way you want (without changing the method name or params), ant it will work.

Rails 3 delayed_job start after rebooting

I have my rails site deployed under apache. The apache is run as a service. Now I have added delayed_job there and things work fine.
Now I want to start the workers together with apache, e.g, After rebooting the server, my site and workers are up and ready so I don't have to log in and type "sudo RAILS_ENV=production script/delayed_job -n 2 start".
Another issue is that whenever I want to start the delayed_job I have to use "sudo"...
Any idea how to avoid those 2 issues?
Thanks for your help.
Use the whenever gem and its 'every :reboot' functionality. In schedule.rb:
environment = ENV['RAILS_ENV'] || 'production'
every :reboot do
command "cd #{path} && #{environment_variable}=#{environment} bin/delayed_job --pool=queue1:2, --pool=queue2,queue3:1 restart"
end
Could you just create a shell script to execute the commands you need?
#!/bin/sh
# stop delayed job
# restart apache
apachectl restart
# start delayed job
sudo RAILS_ENV=production script/delayed_job -n 2 start
It sounds like you want to have delayed_job automatically start after apache starts when you boot up the hardware. If that's the case you need to write an init script in /etc/init.d or /etc/rc.d/init.d (depending on your system). This page gives a decent primer on this:
http://www.philchen.com/2007/06/04/quick-and-dirty-how-to-write-and-init-script

Rails + Postgres drop error: database is being accessed by other users

I have a rails application running over Postgres.
I have two servers: one for testing and the other for production.
Very often I need to clone the production DB on the test server.
The command I'm runnig via Vlad is:
rake RAILS_ENV='test_server' db:drop db:create
The problem I'm having is that I receive the following error:
ActiveRecord::StatementInvalid: PGError: ERROR: database <database_name> is being accessed by other users DROP DATABASE IF EXISTS <database_name>
This happens if someone has accessed the application via web recently (postgres keeps a "session" opened)
Is there any way that I can terminate the sessions on the postgres DB?
Thank you.
Edit
I can delete the database using phppgadmin's interface but not with the rake task.
How can I replicate phppgadmin's drop with a rake task?
If you kill the running postgresql connections for your application, you can then run db:drop just fine. So how to kill those connections? I use the following rake task:
# lib/tasks/kill_postgres_connections.rake
task :kill_postgres_connections => :environment do
db_name = "#{File.basename(Rails.root)}_#{Rails.env}"
sh = <<EOF
ps xa \
| grep postgres: \
| grep #{db_name} \
| grep -v grep \
| awk '{print $1}' \
| xargs kill
EOF
puts `#{sh}`
end
task "db:drop" => :kill_postgres_connections
Killing the connections out from under rails will sometimes cause it to barf the next time you try to load a page, but reloading it again re-establishes the connection.
Easier and more updated way is:
1. Use ps -ef | grep postgres to find the connection #
2. sudo kill -9 "# of the connection
Note: There may be identical PID. Killing one kills all.
Here's a quick way to kill all the connections to your postgres database.
sudo kill -9 `ps -u postgres -o pid`
Warning: this will kill any running processes that the postgres user has open, so make sure you want to do this first.
I use the following rake task to override the Rails drop_database method.
lib/database.rake
require 'active_record/connection_adapters/postgresql_adapter'
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter < AbstractAdapter
def drop_database(name)
raise "Nah, I won't drop the production database" if Rails.env.production?
execute <<-SQL
UPDATE pg_catalog.pg_database
SET datallowconn=false WHERE datname='#{name}'
SQL
execute <<-SQL
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = '#{name}';
SQL
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
end
end
end
end
When we used the "kill processes" method from above, the db:drop was failing (if :kill_postgres_connections was prerequisite). I believe it was because the connection which that rake command was using was being killed. Instead, we are using a sql command to drop the connection. This works as a prerequisite for db:drop, avoids the risk of killing processes via a rather complex command, and it should work on any OS (gentoo required different syntax for kill).
cmd = %(psql -c "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE procpid <> pg_backend_pid();" -d '#{db_name}')
Here is a rake task that reads the database name from database.yml and runs an improved (IMHO) command. It also adds db:kill_postgres_connections as a prerequisite to db:drop. It includes a warning that yells after you upgrade rails, indicating that this patch may no longer be needed.
see: https://gist.github.com/4455341, references included
Step 1
Get a list of all postgres connections with ps -ef | grep postgres
The list will look like this:
502 560 553 0 Thu08am ?? 0:00.69 postgres: checkpointer process
502 565 553 0 Thu08am ?? 0:00.06 postgres: bgworker: logical replication launcher
502 45605 553 0 2:23am ?? 0:00.01 postgres: st myapp_development [local] idle
Step 2
Stop whatever connection you want with sudo kill -9 <pid>, where pid is the value in the second column. In my case, I wanted to stop the last row, with pid 45605, so I use:
sudo kill -9 45605
Please check if your rails console or server is running in another tab and then
stop the rails server and console.
then run
rake db:drop
Let your application close the connection when it's done. PostgreSQL doesn't keep connections open , it's the application keeping the connection.
I wrote a gem called pgreset that will automatically kill connections to the database in question when you run rake db:drop (or db:reset, etc). All you have to do is add it to your Gemfile and this issue should go away. At the time of this writing it works with Rails 4 and up and has been tested on Postgres 9.x. Source code is available on github for anyone interested.
gem 'pgreset'
Rails is likely connecting to the database to drop it but when you log in via phppgadmin it is logging in via the template1 or postgres database, thus you are not affected by it.
This worked for me (rails 6):
rake db:drop:_unsafe
I think we had something in our codebase that initiated a db connection before the rake task attempted to drop it.
After restarting the server or computer, please try again.
It could be the simple solution.
You can simply monkeypatch the ActiveRecord code that does the dropping.
For Rails 3.x:
# lib/tasks/databases.rake
def drop_database(config)
raise 'Only for Postgres...' unless config['adapter'] == 'postgresql'
Rake::Task['environment'].invoke
ActiveRecord::Base.connection.select_all "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname='#{config['database']}' AND state='idle';"
ActiveRecord::Base.establish_connection config.merge('database' => 'postgres', 'schema_search_path' => 'public')
ActiveRecord::Base.connection.drop_database config['database']
end
For Rails 4.x:
# config/initializers/postgresql_database_tasks.rb
module ActiveRecord
module Tasks
class PostgreSQLDatabaseTasks
def drop
establish_master_connection
connection.select_all "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname='#{configuration['database']}' AND state='idle';"
connection.drop_database configuration['database']
end
end
end
end
(from: http://www.krautcomputing.com/blog/2014/01/10/how-to-drop-your-postgres-database-with-rails-4/)
I had this same issue when working with a Rails 5.2 application and PostgreSQL database in production.
Here's how I solved it:
First, log out every connection to the database server on the PGAdmin Client if any.
Stop every session using the database from the terminal.
sudo kill -9 `ps -u postgres -o pid=`
Start the PostgreSQL server, since the kill operation above stopped the PostgreSQL server.
sudo systemctl start postgresql
Drop the database in the production environment appending the production arguments.
rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1
That's all.
I hope this helps
[OSX][Development/Test] Sometimes it is hard to determine the proper PID when you have a lot of PostgreSQL processes like checkpointer, autovacuum launcher, etc. In this case, you can simply run:
brew services restart postgresql#12
If you dockerized your app, then restart your db service
sudo docker-compose restart db
Just make sure that the you have exited the rails console on any open terminal window and exited the rails server...this is one of the most common mistake made by people
I had a similar error saying 1 user was using the database, I realized it was ME! I shut down my rails server and then did the rake:drop command and it worked!
Solution
Bash script
ENV=development
# restart postgresql
brew services restart postgresql
# get name of the db from rails app
RAILS_CONSOLE_COMMAND="bundle exec rails c -e $ENV"
DB_NAME=$(echo 'ActiveRecord::Base.connection_config[:database]' | $RAILS_CONSOLE_COMMAND | tail -2 | tr -d '\"')
# delete all connections to $DB_NAME
for pid in $(ps -ef | grep $DB_NAME | awk {'print$2'})
do
kill -9 $pid
done
# drop db
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 RAILS_ENV=$ENV bundle exec rails db:drop:_unsafe
ActiveRecord::StatementInvalid: PG::ObjectInUse: ERROR: database "database_enviroment" is being accessed by other users
DETAIL: There is 1 other session using the database.
For rails 7: you can use -> rails db:purge

Resources