Actioncable broadcast not working from console in Rails - ruby-on-rails

I used actioncable on rails 5 app. Below code work in controller but not in console.
ActionCable.server.broadcast "connector_app", content: "test message"
Response:
[ActionCable] Broadcasting to connector_app: {:content=>"test message"}
=> nil
cable.yml
development:
adapter: redis
url: redis://localhost:6379/1
test:
adapter: async
production:
adapter: redis
url: redis://localhost:6379/1
Contoller code( It works properly):
def sample_socket_message
ActionCable.server.broadcast "connector_app",
content: "test message",
head :ok
end
Problem Solved:
Forget to add below code in config/initializer/redis.rb
$redis = Redis.new(:host => 'localhost', :port => 6379)

The default behavior for ActionCable in development and test mode is to use the async adapter, which operates within the same process only. For inter-process broadcasting, you will need to switch to the redis adapter.
Since you are using redis adapter in development that's why it is working in controller and not working in console.
cable.yml
test:
adapter: redis
url: redis://localhost:6379/1

Related

ActionCable and Heroku Redis configuration

Last week RedisToGo was terminated on Herokum, leaving me with no choice but to find an alternative. I got a new subscription from Heroku: Heroku Redis.
Everything seems to work fine (all tasks/jobs) except things related to ActionCable.
[ActionCable] [#######] Registered connection (#########)
2022-08-17T00:40:23.213184+00:00 app[web.1]: #<Thread:0x00007e######/app/vendor/bundle/ruby/2.6.0/gems/actioncable-5.1.7/lib/action_cable/subscription_adapter/redis.rb:144 run> terminated with exception (report_on_exception is true):
2022-08-17T00:40:23.213206+00:00 app[web.1]: /app/vendor/bundle/ruby/2.6.0/gems/redis-4.1.4/lib/redis/client.rb:268:in `rescue in io': Connection lost (ECONNRESET) (Redis::ConnectionError)
I spent the last few days trying all sort of trick, but nothing work.
My cable.yml file looks like:
production:
adapter: redis
url: <%= ENV['REDIS_URL'] %>
my redis.rb file looks like this:
uri = if Rails.env == 'production'
URI.parse(ENV["REDIS_URL"])
else
URI.parse("redis://localhost:6379")
end
Resque.redis = Redis.new(host: uri.host, port: uri.port, password: uri.password, ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE })
Am I missing certain parameters that results in the error ?
I use Heroku Redis and here's what my cable.yml looks like:
development:
adapter: redis
url: redis://localhost:6379/1
channel_prefix: myapp_development
test:
adapter: redis
url: redis://localhost:6379/1
channel_prefix: myapp_test
production:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
channel_prefix: myapp_production
ssl_params:
verify_mode: <%= OpenSSL::SSL::VERIFY_NONE %>
If your tasks and jobs don't use Redis (if ActionCable is the only thing trying to use Redis) then your Redis might not actually be set up properly. Here's the documentation.
Check to make sure Heroku actually set a REDIS_URL env variable:
$ heroku config | grep REDIS
> REDIS_URL: redis://h:asdfqwer1234asdf#ec2-111-1-1-1.compute-1.amazonaws.com:111
Make sure your instance has a normal configuration:
https://devcenter.heroku.com/articles/heroku-redis#configuring-your-instance
Two other helpful sources:
How to solve the SSL error for Redis 6 on Heroku
ActionCable Redis adapter crashes with Heroku Redis 6

Separate read/write configuration/setup for Rails 7 application

rails 7
AWS Aurora RDS Cluster with one write endpoint and one read endpoint
I would like to configure my Rails application to use one endpoint to write and one endpoint to read for the production environment, and a single endpoint for reading/writing in the test environment.
Reading through the documentation, it seems as what I need to do, is that I need to do the following (assuming a production .
In /config/database.yml:
production:
primary:
database: my_primary_database
username: root
password: <%= ENV['PRIDUCTION_ROOT_PASSWORD'] %>
adapter: mysql2
primary_replica:
database: my_primary_database
username: root
password: <%= ENV['PRIDUCTION_ROOT_PASSWORD'] %>
adapter: mysql2
replica: true
test:
database: my_test_database
username: root
password: <%= ENV['TEST_PASSWORD'] %>
adapter: mysql2
Note: the documentation mentions that the username for the writers and replicas should be different, but the AWS Aurora cluster will not allow me to do that. Is this a recommendation or a must?
And this is what I should have in my /app/models/application_record.rb:
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
if Rails.env == 'production'
connects_to database: { writing: :primary, reading: :primary_replica }
end
end
Then, run the following command:
rails g active_record:multi_db
Which will generate the file: config/initializers/multi_db.rb and inside that file do:
Rails.application.configure do
if Rails.env == 'production'
config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver =
ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end
end
Am I missing anything, or do I need to add the following to config/environments/production.rb?
config.active_record.writing_role = :default
config.active_record.reading_role = :readonly
Anything else?

Getting Action Cable to broadcast in Sidekiq Job

I'm using Rails 5 in a docker environment and I can get Action Cable to broadcast on a Sidekiq worker perfectly fine, using worker.new.perform.
But for the life of me, I cannot get it to broadcast while using worker.perform_async.
Here is my cable.yml:
default: &default
adapter: redis
url: <%= ENV['REDIS_PROVIDER'] %>
development:
<<: *default
test:
<<: *default
production:
<<: *default
Here is my worker:
class AdminWorker
include Sidekiq::Worker
def perform
ActionCable.server.broadcast 'admin_channel', content: 'hello'
end
end
My Admin Channel:
class AdminChannel < ApplicationCable::Channel
def subscribed
stream_from "admin_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
As I mentioned earlier, this works just fine when calling AdminWorker.new.perform. As soon as I try to run AdminWorker.perform_async, the cable will not broadcast and nothing helpful regarding action cable in the logs. What am I missing here?
I had the same problem. Came across this answer: ActionCable.server.broadcast from the console - worked for me. Basically just changed cable.yml
development:
adapter: async
to
development:
adapter: redis
url: redis://localhost:6379/1
and I was able to broadcast from console, models, Sidekiq worker classes, etc.
For those who wants to dockerize rails and sidekiq, you should run action_cable server separately like
puma -p 28080 cable/config.ru
https://nickjanetakis.com/blog/dockerize-a-rails-5-postgres-redis-sidekiq-action-cable-app-with-docker-compose
https://github.com/kchrismucheke/dockersample/blob/da5923899fb17682fabed041bef5381ed3fd91ab/config/application.rb#L57-L62
In development environment
By default, ActionCable would run only on the rails server only. And it would not work in Sidekiq, console, cron jobs, etc.
Because in config/cable.yml development server adapter is set to async
Solution:
For ActionCable inter-process broadcasting, you have to set the adapter to Redis
In config/cable.yml
development:
adapter: redis
url: redis://localhost:6379/1
channel_prefix: project_name_development

Is it possible to directly connect to a Heroku database from localhost?

If I have a DATABASE_URL, is it possible to connect to it from localhost? I'm using the following code:
db = URI.parse(database_url)
connection = ActiveRecord::Base.establish_connection(
:adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
:host => db.host,
:username => db.user,
:password => db.password,
:database => db.path[1..-1],
:encoding => 'utf8'
)
When running the code from my pc, I keep getting errors like:
could not connect to server: Connection timed out
Is the server running on host some_host.amazonaws.com and accepting
TCP/IP connections on port 5432?
I'm using the same code to share a database between two apps that are running on Heroku and it works. This leads me to believe that connecting to a Heroku database is restricted unless you perform it from a Heroku host. Is that true?
Indeed SSL is required for outside connections. The underlying postgres adapter can be forced to use SSL with the sslmode=require parameter. You can pass arbitrary parameters down from the ActiveRecord connection options, like so:
ActiveRecord::Base.establish_connection(
adapter: 'postgresql',
host: 'host',
username: 'user',
password: 'pass',
database: 'database_name',
encoding: 'utf-8',
port: '5432', # could be a non-standard port
sslmode: 'require' # force SSL
)
I've verified this locally, and here's a full session showing it work. Please make sure you're not mistyping anything:
heroku pg:credentials yellow -a my-app Connection info string:
"dbname=ddbolrs4g89dsi host=ec2-23-21-91-108.compute-1.amazonaws.com port=5432 user=itkdrxzjmwcjtw password=wU-4tT3YbF8AZ3U5kwu-2KYPEX ssl
mode=require"
$ irb
> require 'active_record'
=> true
> ActiveRecord::Base.establish_connection(adapter: 'postgresql', database: 'ddbolrs4g89dsi', host: 'ec2-23-21-91-108.compute-1.amazonaws.com', username: 'itkdrxzjmwcjtw', password: 'wU-4tT3YbF8AZ3U5kwu-2KYPEX', sslmodel: 'require')
=> #<ActiveRecord::ConnectionAdapters::ConnectionPool:0x007f7f9ba6f0f0 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Mutex:0x007f7f9ba6f078>, #spec=#<ActiveRecord::Base::ConnectionSpecification:0x007f7f9ba64150 #config={:adapter=>"postgresql", :database=>"ddbolrs4g89dsi", :host=>"ec2-23-21-91-108.compute-1.amazonaws.com", :username=>"itkdrxzjmwcjtw", :password=>"wU-4tT3YbF8AZ3U5kwu-2KYPEX", :sslmodel=>"require"}, #adapter_method="postgresql_connection">, #reserved_connections={}, #queue=#<MonitorMixin::ConditionVariable:0x007f7f9ba6f000 #monitor=#<ActiveRecord::ConnectionAdapters::ConnectionPool:0x007f7f9ba6f0f0 ...>, #cond=#<ConditionVariable:0x007f7f9ba6efd8 #waiters=[], #waiters_mutex=#<Mutex:0x007f7f9ba6ef88>>>, #timeout=5, #size=5, #connections=[], #automatic_reconnect=true>
> ActiveRecord::Base.connection.execute("SELECT version()").first
=> {"version"=>"PostgreSQL 9.1.4 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3, 64-bit"}
> exit
$ # remove db, leaked creds ^
$ heroku addons:remove HEROKU_POSTGRESQL_YELLOW -a my-app --confirm my-app
Removing HEROKU_POSTGRESQL_YELLOW on my-app... done, v490 (free)
Outside connection to the postgresql server require SSL on Heroku. Have a look at the docs as well.

Mongoid Production Issue: Failed to connect to a master node

I've switched away from Mongo_Mapper to Mongoid and am having trouble deploying to production, for some reason. I'm using NGINX, Rails 3.1, and Passenger. I keep getting this message, "Failed to connect to a master node at myusernamehere:27017 (Mongo::ConnectionFailure)".
defaults: &defaults
host: localhost
# slaves:
# - host: slave1.local
# port: 27018
# - host: slave2.local
# port: 27019
development:
<<: *defaults
database: s3uploadergen_development
test:
<<: *defaults
database: s3uploadergen_test
production:
host: localhost
port: 27017
database: mydbnamehere
username: myuserhere
password: mypasswordhere
I've triple-checked all settings and tried the ENV approach as well (adding the ENV variables to production.rb and calling them via the documented mongoid approach but had the same issue):
production:
host: <%= ENV['MONGOID_HOST'] %>
port: <%= ENV['MONGOID_PORT'] %>
username: <%= ENV['MONGOID_USERNAME'] %>
password: <%= ENV['MONGOID_PASSWORD'] %>
database: <%= ENV['MONGOID_DATABASE'] %>
Ideally, I want to just specify it either in production.rb or an initializer of some sort.
I'm assuming that by "documented mongoid approach" you mean setting the recommended "uri" param instead of all those different setttings. You might want to try it since it's the recommended way of doing it.
defaults: &defaults
persist_in_safe_mode: true
development:
<<: *defaults
host: localhost
database: app_development
test:
<<: *defaults
host: localhost
database: app_test
production:
<<: *defaults
uri: <%= ENV['MONGOHQ_URL'] %>
Note that I do use Heroku but I don't use the MongoHQ add on. I just use it directly, so I manually set my MONGOHQ_URL. Your uri would look something like:
mongodb://<user>:<password>#<the.db.host.com>:<port>/<database_name>
Looks to me like you can't connect to "localhost" based on the error (like maybe you need the full host name or IP or something?). Anything in your app logs?
Just make sure not to set "host" and "uri" on any of the ENV's because "host" will override the setting that is derived from the uri.

Resources