Heroku Redis cant open connection - ruby-on-rails

I following Ryan Bates tutorial ActionController Live, and deploying app at heroku. All works fine, except events, where Ryan sad that we should reopen the redis connection, and I cant do it. I using RedisToGo to perform redis on heroku.
Here my events controller action:
def events
response.headers["Content-Type"] = "text/event-stream"
redis = Redis.new(:url => uri)
redis.psubscribe('messages.*') do |on|
on.pmessage do |pattern, event, data|
response.stream.write("event: #{event}\n")
response.stream.write("data: #{data}\n\n")
end
end
rescue IOError
logger.info "Stream closed"
ensure
redis.quit
response.stream.close
end
Also here redis initializer:
uri = URI.parse(ENV["REDISTOGO_URL"])
REDIS = Redis.new(:url => uri)
Can someone help me?
EDIT
I got all to work just initializing the client using Redis.new(url: ENV["REDISTOGO_URL"]) instead of parsing the URI in events controller action.

replace this:
redis = Redis.new(:url => uri)
redis.psubscribe
with this:
REDIS.psubscribe
anywhere you have 'redis' above, replace with the REDIS global.

Related

rails global variable inaccessible in thread

I'm using Faye websockets and Redis to attempt a master/client websocket setup for a slideshow presentation.
The clients' should all follow along with the master (i.e. the master moves forward a slide, a message is sent out to all of the clients, and they all move forward a slide).
The issue I'm having is that my list of client websockets is empty when I access inside the thread created in the initialize function. The separate thread is necessary as Redis' 'subscribe' is a blocking function.
This file is a middleware and runs on app boot up.
I know that the point of global variables in rails is that they're shared across threads, but in my case something seems to be preventing it.
Is there a way to store a list of websockets in a globally accessible place? Globally, as in, for all running instances of the app on the same server.
(can't use Redis for that cause it can't store objects).
require 'faye/websocket'
require 'redis'
class WsCommunication
KEEPALIVE_TIME = 15 #seconds
CHANNEL = 'vip'
def initialize(app)
#app = app
$clients = []
uri = URI.parse(ENV['REDISCLOUD_URL'])
Thread.new do
redis_sub = Redis.new(host: uri.host, port: uri.port, password: uri.password)
redis_sub.subscribe(CHANNEL) do |on|
on.message do |channel, msg|
puts 'client list on thread'
puts $clients
#### prints nothing
$clients.each { |ws| ws.send(msg) }
end
end
end
end
def call(env)
if Faye::WebSocket.websocket?(env)
ws = Faye::WebSocket.new(env, nil, {ping: KEEPALIVE_TIME})
ws.on :open do |event|
$clients << ws
end
ws.on :message do |event|
puts 'client list'
puts $clients
### prints the full list of clients
$redis.publish(CHANNEL, event.data)
end
ws.on :close do |event|
$clients.delete(ws)
ws = nil
end
# Return async Rack response
ws.rack_response
else
#app.call(env)
end
end
end

Configure Redis connection on initialize

I'm using Predictor gem and when I attempt to start the gem shows:
"redis not configured! - Predictor.redis = Redis.new" (RuntimeError)
So, how to configure Redis Connection on initialize?
thank's
This is how Redis is initialized in general.
Firstly, a good practice would be adding this to your config/environments/[environment_name].rb. So you can maintain different locations for Redis when you change environments.
config.redis_host = "localhost"
Then in your application's config/initializers path create redis.rb and place the code below to initialize Redis.
require 'redis'
## Added rescue condition if Redis connection is failed
begin
$redis = Redis.new(:host => Rails.configuration.redis_host, :port => 6379)
rescue Exception => e
puts e
end
Then you'll be able to use the global variable $redis within your application for Redis-related commands.
$redis.hset "my_hash", item.id, business.id
Here is a helpful article with more details.
Now in your case as this documentation suggests, here is what you should do:
In config/initializers/predictor.rb,
Predictor.redis = Redis.new(:url => ENV["PREDICTOR_REDIS"])
Or, to improve performance, add hiredis as your driver (you'll need to install the hiredis gem first)
Predictor.redis = Redis.new(:url => ENV["PREDICTOR_REDIS"], :driver => :hiredis)
Then, be sure to include include Predictor::Base in all models you want to use it,
class CourseRecommender
include Predictor::Base
...
end
Here is the code responsible for the error you getting.

How to send ExceptionNotifier from a queue?

Say I rescue from an Exception and I do:
begin
raise StandardError
rescue StandardError => ex
ExceptionNotifier.notify_exception(ex)
end
end
How can I make that ExceptionNotifier email be sent from a queue? So, it is asynchronous to the process of the application?
In the docs I can see how to send ExceptionNotifier if the error has happened within a worker, but not how to enqueue that sending to a queue.
The queue aspect of Rails has to be handled by a third-party semi-persistent data store. We use Redis & Resque
--
Here is a good tutorial on this:
Initializer
#app/config/initializers/redis.rb
require 'resque/server' #-> allows processing of jobs
require 'resque_scheduler' #-> allows for scheduling
uri = URI.parse(ENV["REDISCLOUD_URL"] ||= "http://localhost:6379")
Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
-
Resque
This will allow you to send data to redis, using your Resque queue to handle it:
def your_action
Resque.enqueue(SendEmail, [[data ref]])
end
-
Queue
Then you can use resque to run through the Redis queue & send the emails:
$ rake resque:work QUEUE='*'
Quite a vague description, I know; but hopefully it will give you an idea as to how to use a third-party queue-based system to handle sending emails for you

Unable to push the method to the rabbitmq queue

I am working on rabbitmq and trying to push a method to a queue from my ruby on rails app and I am running a server side ruby script to read the queue and execute the method which is send in the payload. Here is my client side code.
module Rabbitesh
require 'amqp'
#debugger
def self.call_rabbits(payload,queue_name)
AMQP.start(:host => "localhost") do |connection|
channel = AMQP::Channel.new(connection)
queue = channel.queue(queue_name)
channel.default_exchange.publish(payload, :routing_key => queue.name)
#EM.add_timer(0.01) do
connection.close do
#end
end
end
end
end
This is now I call the Rabbitmq function
Rabbitesh::call_rabbits(obj,"welcome_mail")
where "welcome_mail" is the queue_name
This is the server side script
require 'rubygems'
require 'amqp'
require 'daemons'
options = { :backtrace => true, :dir => '.', :log_output => true}
Daemons.run_proc('raabbitmq_daemon',options) do
AMQP.start(:host => "localhost") do |connection|
channel = AMQP::Channel.new(connection)
queue = channel.queue("welcome_mail")
Signal.trap("INT") do
connection.close do
EM.stop { exit }
end
end
puts " [*] Waiting for messages. To exit press CTRL+C"
queue.subscribe do |body|
UserMailers.welcome_organic(body).deliver
end
end
end
The problem is when my rails app calls the rabbitmq function the console stops there saying "updating client properties" and though I will be running my server side ruby script, it will not read the queue and take execute the process. I am not able to understand whats wrong with the code, kindly help me out.

Rails + TweetStream gem reconnecting

Hey, I just tested the TweetStream gem.
Example:
TweetStream::Client.new('myuser','mypass').track('ruby', 'rails') do |status|
puts "[#{status.user.screen_name}] #{status.text}"
end
This example works.
Questions:
I tried restarting my router (internet connection lost) and after that no new messages have arrived. Can someone explain this behavior to me?
I tested the daemon. What happens if no internet connection is available for a day or more? Will it reconnect automatically?
I like Rufus gem (for background processes). Can I somehow integrate this code with Rufus where I would check if the process is still active?
My reconnect solution (config/initializers/tweet_stream.rb):
client = nil
scheduler = Rufus::Scheduler.start_new
scheduler.every '30min', :first_in => '1s' do |job|
client.stop rescue nil
client = TweetStream::Client.new('user','pass').on_error do |message|
Rails.logger.info "[Rufus][#{Time.now}] TweetStream error: #{message}"
end.track('love') do |status|
Rails.logger.error "[TweetStream] Status: #{status.id}"
end
end
Thx!

Resources