Resque Workers on Heroku locked out of Postgres DB SSL- no fix yet - postgresql

I'm using resque/redis on heroku to send emails as a background job. It works fine for the first email I send, but after that I get the error: (ActiveRecord::StatementInvalid: PG::Error: SSL error: decryption failed or bad record mac :) ...
I've seen the other questions/answers that say to add to an initializer:
Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
OR
Resque.before_fork = Proc.new { ActiveRecord::Base.establish_connection }
However, I have done this (and tried any other thing I can think of) and I'm still getting the same error. I have run the code with only before_fork and only after_fork to no avail.
I am also using APN_sender to send apple push notifications. The workers for these have had no problems (but I'm calling default Heroku workers to do these rather than Resque workers).
Here are my relevant files, please help! This is my first SO question as well.. apologies if it's not done perfectly.
#config/resque.rb
after_fork do |server, worker, resque|
logger.info("Got to after_fork in resque.rb config file")
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
--------------------
#config/initializers/resque.rb
require 'resque'
require 'resque/server'
heroku_environments = ["staging", "production"]
rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
rails_env = ENV['RAILS_ENV'] || 'development'
#confusing wording.. determines whether or not we are in Production, tested and working
unless heroku_environments.include?(rails_env)
resque_config = YAML.load_file(rails_root + '/config/resque.yml')
Resque.redis = resque_config[rails_env]
else
uri = URI.parse(ENV["REDISTOGO_URL"] || "redis://localhost:6379/")
Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
end
----------------------
#resque.rake
require 'resque/tasks'
task "resque:setup" => :environment do
ENV['QUEUE'] = '*'
Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
Resque.before_fork = Proc.new { ActiveRecord::Base.establish_connection }
end
task "apn:setup" => :environment do
ENV['QUEUE'] = '*'
end
desc "Alias for resque:work (To run workers on Heroku)"
task "jobs:work" => "resque:work"
desc "Alias for apn:work (To run workers on Heroku)"
task "jobs:work" => "apn:work"
-----------------------
#Sending the email
#event.guests.each do |g|
Resque.enqueue(MailerCallback, "Notifier", :time_change, #event.id, g.id)
end
I am running one Heroku worker and one Resque worker from the Heroku ps:scale command. As I said, the first email sends error-free, and then any emails after get the above error.
Thanks in advance!
Mike

OK, so couldn't figure this out...
Switched over to delayed job and it's working much better. A little frustrating that I can't send push notifications with apn_sender anymore, but apn_on_rails is working fine.
Weird problem, still curious...

Related

Celery chain - if any tasks fail, do x, else y

I'm just getting into Celery chains in my Django project. I have the following function:
def orchestrate_tasks_for_account(account_id):
# Get the account, set status to 'SYNC' until the chain is complete
account = Account.objects.get(id=account_id)
account.status = "SYNC"
account.save()
chain = task1.s(account_id) | task2.s() | task3.s()
chain()
# if any of the tasks in the chain failed, set account.status = 'ERROR'
# else set the account.status = 'OK'
The chain works as expected, but I'm not sure how to take feedback from the chain and update the account based on the results
In other words, I'd like to set the account status to 'ERROR' if any of the tasks in the chain fail, otherwise I'd like to set the account status to 'OK'
I'm confused by the Celery documentation on how to handle an error with an if/else like I've commented in the last two lines above.
Does anyone have experience with this?
Ok - here's what I came up with
I've leveraged the waiting library in this solution
from celery import chain
from waiting import wait
def orchestrate_tasks_for_account(account_id):
account = Account.objects.get(id=account_id)
account.status = "SYNC"
account.save()
job = chain(
task1.s(account_id),
task2.s(),
task3.s()
)
result = job.apply_async()
wait(
lambda: result.ready(), # when async job is completed...
timeout_seconds=1800, # wait 1800 seconds (30 minutes)
waiting_for="task orchestration to complete"
)
if result.successful():
account.status = 'OK'
else:
account.status = 'ERROR'
account.save()
I am open to suggestions to make this better!

How can I check the connection of Mongoid

Does Mongoid has any method like ActiveRecord::Base.connected??
I want to check if the connection that's accessible.
We wanted to implement a health check for our running Mongoid client that tells us whether the established connection is still alive. This is what we came up with:
Mongoid.default_client.database_names.present?
Basically it takes your current client and tries to query the databases on its connected server. If this server is down, you will run into a timeout, which you can catch.
My solution:
def check_mongoid_connection
mongoid_config = File.read("#{Rails.root}/config/mongoid.yml")
config = YAML.load(mongoid_config)[Rails.env].symbolize_keys
host, db_name, user_name, password = config[:host], config[:database], config[:username], config[:password]
port = config[:port] || Mongo::Connection::DEFAULT_PORT
db_connection = Mongo::Connection.new(host, port).db(db_name)
db_connection.authenticate(user_name, password) unless (user_name.nil? || password.nil?)
db_connection.collection_names
return { status: :ok }
rescue Exception => e
return { status: :error, data: { message: e.to_s } }
end
snrlx's answer is great.
I use following in my puma config file, FYI:
before_fork do
begin
# load configuration
Mongoid.load!(File.expand_path('../../mongoid.yml', __dir__), :development)
fail('Default client db check failed, is db connective?') unless Mongoid.default_client.database_names.present?
rescue => exception
# raise runtime error
fail("connect to database failed: #{exception.message}")
end
end
One thing to remind is the default server_selection_timeout is 30 seconds, which is too long for db status check at least in development, you can modify this in your mongoid.yml.

google-api-client suddenly comes back with "invalid request"

I've been running Ruby scripts for weeks now using a Service Account, but today I'm getting an "Invalid Request" when I try to build the client using the following function:
def build_client(user_email)
client = Google::APIClient.new
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => 'https://www.googleapis.com/auth/calendar',
:issuer => SERVICE_ACCOUNT_EMAIL,
:signing_key => Google::APIClient::KeyUtils.load_from_pkcs12(SERVICE_ACCOUNT_PKCS12_FILE_PATH, "notasecret"),
:person => user_email
)
client.authorization.fetch_access_token!
return client
end
Is there a lifespan on Service Accounts? I tried creating another Service Account and using that but I get the same result:
Authorization failed. Server message: (Signet::AuthorizationError)
{
"error" : "invalid_request"
}
Stumped!
OK. I figured it out. It was all to do with the user_email. I was reading it from a file and forgot to chomp the linefeed off, so it was objecting to a mal-formed email address.

Setting env when using rspec to test omniauth callbacks

I'm having a strange problem when trying to set a callback for Facebook Authentication via Omniauth. In my controller (simplified to just the code necessary to show the error) I have:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
raise env.inspect
# auth_hash = env["omniauth.auth"]
end
end
this works in production mode, showing me the hash. However in test mode env is set to nil.
I have the following set in my spec_helper.rb file
OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:facebook, {"credentials" => {
"token" => "foo-token"
}
})
and my spec looks like this:
require 'spec_helper'
describe Users::OmniauthCallbacksController do
describe "Facebook" do
before(:each) do
request.env["devise.mapping"] = Devise.mappings[:user]
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:facebook]
end
it "should be a redirect" do
get :facebook
response.should redirect_to(root_path)
end
end
end
Can anyone enlighten me on what I need to do to have env not be nil when running my tests?
I use the following in my spec_helper.rb :
RACK_ENV = ENV['ENVIRONMENT'] ||= 'test'
I don't use Rails or Devise though so YMMV. I've also seen various threads saying that someone had to do this before their requires to get it to work.

500 error when calling webservice through rhosync/rhodes

I am trying to call a web service in rhosync application.rb, I see a 500 error response in rhosync console .. and 'server returned an error' in BB simulator .. :(
Some info about my setup -
I have created a rhodes app that connects to a rhosync app when user enters user name and password and clicks on "login". I am calling this webservice through "authenticate" method of application.rb of the rhosync application ..
def authenticate(username,password,session)
Rho::AsyncHttp.get(:url => 'http://mywebserviceURL',:callback => (url_for :action => :httpget_callback),:callback_param => "" )
end
UPDATE
Instead of http:async, I tried consuming a soap based webservice and it worked just fine .. here is code if anyone cones here in search of a sample.. in application.rb of rhosync app
require "soap/rpc/driver"
class Application < Rhosync::Base
class << self
def authenticate(username,password,session)
driver = SOAP::RPC::Driver.new('http://webserviceurl')
driver.add_method('authenticate', 'username', 'password')
ret=driver.authenticate(username,password)
if ret=="Success" then
true
else
false
end
end
end
Application.initializer(ROOT_PATH)
You can typically find the problem if you crank up your log. Edit rhoconfig.txt in your app
set these properties -
# Rhodes runtime properties
MinSeverity = 1
LogToOutput = 1
LogCategories = *
ExcludeLogCategories =
then try again and watch the terminal output. Feel free to post the log back and I'll take a look.
You also might want to echo out puts the mywebserviceURL if you're using that as a variable, I trust you just changed that for the post here. Can you access the webservice if you hit it with a browser?
require "soap/rpc/driver"
class Application < Rhosync::Base
class << self
def authenticate(username,password,session)
driver = SOAP::RPC::Driver.new('http://webserviceurl')
driver.add_method('authenticate', 'username', 'password')
ret=driver.authenticate(username,password)
if ret=="Success" then
true
else
false
end
end
end
Application.initializer(ROOT_PATH)
in this what is done in add_method and authenticate method and where it to be written.