Using Faye on Heroku in production mode
Asked Answered
B

1

5

Rails 4.1.1
Ruby 2.1.1 The access point is https://pacific-savannah-8641.herokuapp.com

Gemfile

source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.1'
# Use mysql as the database for Active Record
gem 'mysql2'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer',  platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0',          group: :doc

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use unicorn as the app server
# gem 'unicorn'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

# Use debugger
# gem 'debugger', group: [:development, :test]

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin]

gem 'slim-rails'
gem 'devise'
gem 'cancan'
gem 'rakismet'

gem 'carrierwave'
gem 'rmagick', :require => false
gem 'faker', '1.0.1'
gem 'jdbc-mysql', '5.1.28', :platform => :jruby
gem 'thinking-sphinx', '~> 3.1.0'
gem 'remotipart', '~> 1.2'
gem 'kaminari'
gem 'thin'
gem 'carrierwave-aws'

group :production do
  gem 'rails_12factor', '0.0.2'
end

gem 'foreman'
gem 'faye'

faye.ru

require 'faye'
Faye::WebSocket.load_adapter('thin')
faye_server = Faye::RackAdapter.new(:mount => '/faye', :timeout => 45)
run faye_server

application.html.slim

doctype html
html
  head
    title Help Desk App

    = stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true
    = javascript_include_tag "application", "data-turbolinks-track" => true
    = javascript_include_tag  "http://localhost:9292/faye.js"

    = csrf_meta_tags
    ....

Procfile

worker: bundle exec foreman start -f Procfile.workers

Procfile.workers

faye_worker: rackup faye.ru -s thin -E production

app/assets/javascripts/main.js

$(function() {
  var faye = new Faye.Client('http://localhost:9292/faye');
  faye.subscribe('/posts/new', function (data) {
      eval(data);
  });  
}

app/helpers/application_helper.rb

module ApplicationHelper
  def broadcast(channel, &block)
    message = {:channel => channel, :data => capture(&block)}
    uri = URI.parse("http://localhost:9292/faye")
    Net::HTTP.post_form(uri, :message => message.to_json)  
  end
end

heroku ps

drobazko@drobazko:~/www/help_desk$ heroku ps
=== run: one-off processes
run.2182 (1X): up 2015/02/11 08:07:57 (~ 27m ago): `foreman start`

=== web (1X): `bin/rails server -p $PORT -e $RAILS_ENV`
web.1: up 2015/02/11 08:35:44 (~ -40s ago)

=== worker (1X): `bundle exec foreman start -f Procfile.workers`
worker.1: up 2015/02/11 08:35:42 (~ -38s ago)
worker.2: up 2015/02/11 08:35:39 (~ -35s ago)
worker.3: up 2015/02/11 08:35:40 (~ -37s ago)
worker.4: up 2015/02/11 08:35:39 (~ -36s ago)

I couldn't find faye.js: Obviously, the reference http://localhost:9292/faye.js is not accessible.

I have tried to find faye.js without success:

https://pacific-savannah-8641.herokuapp.com/faye.js
https://pacific-savannah-8641.herokuapp.com/faye
http://pacific-savannah-8641.herokuapp.com/faye
http://pacific-savannah-8641.herokuapp.com/faye.js
...http://pacific-savannah-8641.herokuapp.com:9292...

Questions:

How should I replace the reference http://localhost:9292/faye in production on Heroku so that it works?

Bibby answered 11/2, 2015 at 15:30 Comment(0)
B
7

I have found the solution.
To use Faye with Heroku without need to add extra dynos (i.e. for free) you should mount Faye to your applications as middleware.
The key point is adding particular lines to application.rb:

require File.expand_path('../boot', __FILE__)

require 'rails/all'
require 'net/http'

Bundler.require(*Rails.groups)

module Helpdesk
  class Application < Rails::Application
    config.middleware.delete Rack::Lock
    config.middleware.use FayeRails::Middleware, mount: '/faye', :timeout => 25
  end
end

Also, you should add faye-rails gem:

gem 'faye-rails', '~> 2.0'

application.js should look as:

//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//= require jquery.remotipart
//= require turbolinks
//= require faye
//= require_tree .

Then, I have created apps/assets/javascripts/realtime.js.coffee to define how I will handle a realtime messages form server:

window.client = new Faye.Client('/faye')

jQuery ->
  client.subscribe '/comments', (payload) ->
    $('.ticket-' + payload.token + ' .no-posts').remove()

    $('<div></div>')
      .css({'backgroundColor' : '#ff9f5f'})
      .prependTo('.ticket-' + payload.token + ' .posts')
      .hide()
      .append(payload.message)
      .fadeIn('slow')
      .css({transition: 'background-color 3s ease-in-out', "background-color": "white"})

Finally, here is how I publish a message to all subscribers app/views/posts/create.js.coffee:

publisher = client.publish('/comments', {
  message: '<%= j render @post %>',
  token: '<%= @ticket.token %>'
});

Procfile should be with the content:

web: bundle exec rails server thin -p $PORT -e $RACK_ENV

You can check all code out on help_desk

Bibby answered 19/2, 2015 at 8:9 Comment(2)
Thanks very much for this, seems to work-ish, 30-sec delay on the free 1 dyno Heroku plan for me but still better than nothing until I look into paid options like Pusher.Habitant
How would you publish a message to all subscribers from controller?Collyrium

© 2022 - 2024 — McMap. All rights reserved.