Environment variables not correctly set - ruby-on-rails

I am using whenever gem. I wanted to set my env variables prior to the scheduled task. The 2nd line in the code below was the command I wanted to run in my schedule.rb file. But looks like I can't get it done so I commented it out and tried in different ways. Still nothing seems to work. Printing env inside the ruby code seems to show the needed variable correctly, but after running 'bundle exec whenever' and checking in the terminal with env command, the variables do not seem to be there. What is wrong here ?
every :hour do
# Run shell script to assign variables and continue the rake task
#system "for line in `cat config/myEnvFile.env` ; do export $line ; done"
f = File.open("config/myEnvFile.env", "r")
f.each_line do |line|
j = line.split(" ")
arr = j.first.split("=")
system "export #{arr[0]}=#{arr[1]}"
system "env"
# This line below is also another way but still nothing works
ENV[arr[0]] = arr[1]
end
rake "task:continue_doing_my_task"
end

The code in your every-block is executed when whenever --update-crontab runs, not every hour.
You need to make the command generated by rake "task:continue_doing_my_task" load these variables, either exporting them in-line using bash syntax (which gets ugly) or using dotenv as suggested in the comment by #Anthony.
See my answer to your follow-up question, which explains this in more detail.

Related

Deployed digitalocean app isn't reading environment variables

I have deployed an app to digitalocean using the Ruby on Rails image. It is set up by default with a user called rails. My rails.service file looks like:
[Unit]
Description=OneMathsExamQuestions
Requires=network.target
[Service]
Type=simple
User=rails
Group=rails
WorkingDirectory=/home/rails/one_maths_exam_questions/
ExecStart=/bin/bash -lc 'bundle exec puma'
TimeoutSec=30s
RestartSec=30s
Restart=always
[Install]
WantedBy=multi-user.target
I need to use some environment variables in my application. So I have added some lines to my /home/rails/.bashrc and /root/.bashrc files (I suspect only the first one should be necessary but neither seems to work):
export A="val1"
export B="val2"
...
Now: if I call echo $A in a terminal I get the expected output. If I go into the Rails console and do ENV["A"] I get the expected output. But my app does not seem to behave correctly (the desired behaviour is connecting to Amazon S3; the exact error is not important).
If I go into my controller and explicitly log the env vars with Rails.logger.debug ENV I just get ENV, and Rails.logger.debug ENV["A"] returns empty string (I guess nil). Similarly if I try to do ENV["RAILS_ENV"] which should definitely work, I get the same. But Rails.env returns "development", as expected.
Moreover, if I explicitly write
ENV["A"] = "val1"
ENV["B"] = "val2"
...
in my config/application.rb, the app works correctly. But this is obviously not a permanent solution, since I can't commit this to version control.
I'm not using the figaro gem, which I think a lot of places are suggesting, but I don't see why I should have to since it works just fine on my local machine.
OK, it looks like if I export my environment variables in .profile then they are picked up by the server no problem. If I remove them from .bashrc then the server has no problems, but I can't get the variables in terminal. I guess they just do different things?

crontab didn't work in Rails rake task

I have a rake task in my Rails application,and when I execute the order in my rails app path /home/hxh/Share/ruby/sport/:
rake get_sportdata
This will work fine.
Now,I want to use crontab to make this rake to be a timed task .so,I add a task:
* * * * * cd /home/hxh/Share/ruby/sport && /usr/local/bin/rake get_sportdata >/dev/null 2>&1
But this doesn't work.I get the log in cron.log file:
Job `cron.daily' terminated
I want to know where the error is.
Does the "cd /home/hxh/Share/ruby/sport && /usr/local/bin/rake get_sportdata >/dev/null 2>&1" can work in your terminal?
But use crontab in Rails normally is not a good idea. It will load Rails environment every time and slow down your performance.
I think whenever or rufus-scheduler are all good. For example, use rufus-scheduler is very easy. In config\initializers\schedule_task.rb
require 'rubygems'
require 'rufus/scheduler'
scheduler = Rufus::Scheduler.start_new(:thread_name => "Check Resources Health")
scheduler.every '1d', :first_at => Time.now do |job|
puts "###########RM Schedule Job - Check Resources Health: #{job.job_id}##########"
begin
HealthChecker.perform
rescue Exception => e
puts e.message
puts e.backtrace
raise "Error in RM Scheduler - Check Resources Health " + e.message
end
end
And implement "perform" or some other class method in your controller, now the controller is "HealthChecker". Very easy and no extra effort. Hope it help.
So that you can test better, and get a handle on whether it works I suggest:
Write a shell script in [app root]/script which sets up the right environment variables to point to Ruby (if necessary) and has the call to rake. E.g., something like script/get-sportdata.sh.
Test the script as root. E.g., first do sudo -s.
Call this script from cron. E.g., * cd [...] && script/get-sportdata.sh. If necessary, test that line as root too.
That's been my recipe for success, running rake tasks from cron on Ubuntu. This is because the cron environment is a bit different than the usual shell setup. And so limiting your actual cron jobs to simple commands to run a particular script are a good way to divide the configuration into smaller parts which can be individually tested.

How do I get an ENV variable set for rspec?

I'm using foreman to start up my rails development server. It's nice that I can put all of my environment variables in the .env file. Is there a way to do something similar for my test environment?
I want to set an API key that I will use with the vcr gem, but I don't want to add the API to version control. Any suggestions besides setting the environment variable manually when I start up my tests script?
If you just need to set environment variables, you can either set them from command-line:
SOMETHING=123 SOMETHING_ELSE="this is a test" rake spec
Or you could define the following at the top of your Rakefile or spec_helper.rb:
ENV['SOMETHING']=123
ENV['SOMETHING_ELSE']="this is a test"
If they don't always apply, you could use a conditional:
if something_needs_to_happen?
ENV['SOMETHING']=123
ENV['SOMETHING_ELSE']="this is a test"
end
If you want to use a Foreman .env file, which looks like:
SOMETHING=123
SOMETHING_ELSE="this is a test"
and turn it into the following and eval it:
ENV['SOMETHING']='123'
ENV['SOMETHING_ELSE']='this is a test'
You might do:
File.open("/path/to/.env", "r").each_line do |line|
a = line.chomp("\n").split('=',2)
a[1].gsub!(/^"|"$/, '') if ['\'','"'].include?(a[1][0])
eval "ENV['#{a[0]}']='#{a[1] || ''}'"
end
though I don't think that would work for multi-line values.
And as #JesseWolgamott noted, it looks like you could use gem 'dotenv-rails'.
You can use the dotenv gem --- it'll work the same as foreman and load from a .env file. (and a .env.test file for your test environments)
https://github.com/bkeepers/dotenv
One option is to alias the rspec command to be a little more specific. Put the following line in your dotfiles (.bashrc or .profile or something).
alias 'rspec'='RACK_ENV=test RAILS_ENV=test bundle exec rspec'
Another option is to put environment variables in specific .env files:
# .env.test
RAILS_ENV=test
MONGODB_URI=mongodb://localhost/test
# .. etc ..
Using the dotenv gem works or you can bring them in manually
$ export $(cat .env.test) && rspec

Clearing crontab changed format of terminal cron messaging

I'm using the latest version of the whenever gem with Rails 3.1.1 for cron tasks. After I used the whenever command on the terminal
whenever -c
to clear the crontab, whenever I type in
crontab -l
whereas it used to say something like "there are no cron tasks" (this is not verbatim) now it just displays a blank space about the size of two empty lines. Also if I have a cron task setup and I type the same command into the terminal again, those two empty lines come up before it shows the cron tasks. I'm sorry if this is a minor issue. Everything appears to be working fine but I just want to make sure I didn't screw anything up that'll come back to haunt me somewhere down the line. Thanks!
You need to change the task in the schedule.rb file which is generated by whenever gem.
After changing your cron task in the schedule.rb you have to update your crontab file and you can use this command to do that :-
whenever --update-crontab f(here f is your application name)
crontab -l is used to see your current crontab file.
Hope it helps

whenever PATH in crontab file for rails 3 ubuntu

I am using whenever gem with rails 3. On my production server (ubuntu) , the runner task does not run. I tried setting the :set job_template to get -l -i as mentioned in this github ticket. However that does not solve the problem.
The problem on this particular production ubuntu is that the ruby path is not there in echo $PATH:
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
Whereas the ruby path is /var/rails/myapp/shared/bundle/ruby/1.8/bin
So if I manually edit the crontab file and add PATH=/var/rails/myapp/shared/bundle/ruby/1.8/bin:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games to the crontab file, the runner task is executed correctly.
However every time I do a deploy, I need to manually edit the crontab file to add the PATH statement to it.
Is there any way in whenever to add this PATH line in crontab file, so that there would not be any need to do this manually after every deploy?
Thanks
I am not using RVM and adding the below code in the file config/schedule.rb(place where u write whenever gem related code) worked for me.
env :PATH, ENV['PATH']
I think if you add /var/rails/myapp/shared/bundle/ruby/1.8/bin to the PATH of whatever user cron is running under on the server, it should be picked up. Or, you could add it in the whenever schedule.rb:
env :PATH, "$PATH:/var/rails/myapp/shared/bundle/ruby/1.8/bin"
That should do the trick, but I haven't tested it.
The answer from idlefingers looks mostly correct, but based on the comment from ami, I would change that line to the following:
env :PATH, "#{ENV["PATH"]}:/var/rails/myapp/shared/bundle/ruby/1.8/bin"
Notice the string interpolation for the environment key for PATH. I have not tested this, but based on ami's comment, this should fully expand the path string in the crontab file as expected.
Add the PATH statement to the top of the crontab file, before the line that starts
# BEGIN Whenever generated tasks for:
and you shouldn't have to manually edit your crontab file every time

Resources