venerdì 14 novembre 2014

Quickly add delayed job to your rails app

In some of my rails app I need to have delayed/background jobs as a consequence of a controller's action call

Below quick instructions on how to add delayed jobs to any rails app:


1- add the following to Gemfile

gem 'delayed_job'
gem 'delayed_job_active_record'
gem 'daemons'


2- execute bundle install

3- create the delayed jobs tables
rails generate delayed_job:active_record

4- migrate the DB
rake db:migrate

5- in your rails root create a directory called jobs

6- add the following lines in config/application.rb
config.autoload_paths += %W(#{config.root}/jobs) #autoload delayed_jobs job
Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.read_ahead = 5 #default value

7- in the jobs directory creare delayed_task.rb
DelayedTask = Struct.new(:x, :y) do

def task_worker
    begin
        res = self.x + self.y
        Rails.logger.info "Task calculating x + y = " + res.to_s
   end
end

def perform
    task_worker
end
end

8- add somewhere in your controller

Delayed::Job.enqueue(DelayedTask.new(2,3), {:priority => 0, :run_at =>  Time.now + 10.seconds})
9- start the jobs worker
rake jobs:work
or
bin/delayed_job start
10- start your raisl app and when your controller method will be called a new delayed job (DelayedTask) will be schedule and execute at the proper time

martedì 26 agosto 2014

How to hot deploy a RedHat Openshift application

Some time when you make a change to your application (in my case is a rails application) you would like to deploy the code change to your running app without restarting the cartridge on Openshift.

By default every time you perform a git push to your Openshift application, the framework execute the entire stop, build, deploy and restart activities.
This might take quite some time and your online application will not be available for few minutes.

However if you want, you can instruct Openshift to Hot Deploy your application, which means git push your code changes without restarting the application.

This will definitely reduce the downtime of your application (in most of the cases only the web server will be restarted and not the entire application cartridge like Ruby or PHP).

Enabling Hot Deploy is easy.
Add an empty hot_deploy file in the .openshift/markers directory.
Deploy this change and Openshift will understand that it should not restart the entire application when you git push your code changes


# touch .openshift/markers/hot_deploy
# git add .
# git commit -m "implementing hot deploy"
# git push


If everything is correct, next time you will push code changes to your Openshift apps, you should see something similar

remote: Not stopping cartridge ruby because hot deploy is enabled

Now your code change will be online in a quite short amount of time and especially with a very limited app downtime.

venerdì 25 luglio 2014

How easily implement PubSub in your application with PubNub

I have recently got interested in PubSub message exchange pattern.
PubSub is a great way to decouple sender and receiver and to scale to large mass of subscribers.
For networking guys, this is somehow similar to multicast. I send my IP multicat packet and I don't know who is receiving it.
In PubSub is the same, Sender app send a message which is not addressed directly to any specific receiver. On the other side Receiver listen to the communication channel without looking for a specific client.

Here I am showing very basic usage of a great service called pubnub.
The service has a free tier for developer and for testing purposed. Should you find this service the right one for your application then you can purchase service directly on pubnub web site.

Anyway, let's see how to publish (send) a message and how to subscribe (receive) a message using pubnub.
I am showing code sample in Ruby, but please note that pubnub provide API/SDK to an impressive number of platform/languages

First of all register to pubnub. You can register with you Google account or create a free account.

After successful registration you will access to a page similar to this one




Here you need to take note of two important information:

  • Subscribe Key: necessary if you want to subscribe to channels and receive messages
  • Publish Key: necessary to send message to a channel

Let's now see the code of a very simple sender and receiver


# sudo gem install pubnub
# pubnub_receive.rb

#!/usr/bin/ruby

require 'pubnub'


pubnub = Pubnub.new(
 :publish_key   => 'your publish key',
    :subscribe_key => 'your subscribekey',
    :error_callback   => lambda { |msg| puts "Error connecting to PubNub: #{msg.inspect}" },
    :connect_callback => lambda { |msg| puts "Connected to PUBNUB: #{msg.inspect}" }
 )

message_cb = lambda { |msg|
 time = Time.now
 puts "-------Received Message-------"
 puts "Channel:: #{msg.channel}"
 puts "Message:: #{msg.message}"
 puts "Message received at #{time}"
 puts "------------------------------"
}

pubnub.subscribe(
    :channel  => 'mancusoa74demo',
    :callback => message_cb
 ) 

while(1) do
 puts "."
  sleep(5)
end

Pubnub.new creates a new pubnub object and connects us to the PubNub service.
You need to specify your publish and subscribe key otherwise you will not be able to send or receive messages.

Now that we have a valid pubnub object, we can subscribe to a channel.
This is done by calling the subscribe method on pubnub object.
We need to pass (at minimum) a channel name. Here I am also specifying a callback which is executed every time we receive a message from the channel.

In the call back I simply print out the channel name, the received message and the time on which the message has been received.

As we want to listen to the channel forever I have add a simple forever loop. This is obviously not appropriate for a real implementation, but you certainly get the point of this simple example.

That's it: this is all what you need to receive message from anywhere in the world, from any device on any platform. Beauty of PubSub pattern :)


# pubnub_send.rb

#!/usr/bin/ruby

require 'pubnub'
 
pubnub = Pubnub.new(
 :publish_key   => 'your publish key',
    :subscribe_key => 'your subscribekey',
    :error_callback   => lambda { |msg| puts "Error connecting to PubNub: #{msg.inspect}" },
    :connect_callback => lambda { |msg| puts "Connected to PUBNUB: #{msg.inspect}" }
 )

pubnub.publish(
 :channel  => 'mancusoa74demo',
    :message => !ARGV[0].nil?? Time.now.to_s + " ## " + ARGV[0] : "empty message",
 ) { |data| puts "Messaage status is #{data.response_message}" }


 sleep(1)


Similarly to sender, also to receive we need to connect to PubNub network and instantiate a Pubnub object.
Unlike the receiver, to send it is not needed to subscribe to a channel.

So in order to publish/send a message we call the publish method on the pubnub object.
You need to pass the channel name and the message you want to send.

Bam!!! as simple as that. You have now sent a message to all your subscribers around the world on different devices and platform. Again beauty of PubSub pattern :)

This model/service can be used for a tons of different purposes. Example: connect with your mobile subscribers, implement a scalable chat/messaging system, implement a scalable logging system, implement a scalable analytics system, ...

In conclusion I hope it is clear from this post that communicate with your subscribers is very simple and PubNub is offering the infrastructure to support your needs.

If you have ideas or experience how to use it in your domain let me know. I am always interested to discover new things.

Cheers

Note: In this post I discuss about pubnub service. I would like to make it very clear that I have absolutely  NO affiliation with pubsub. This is just the description of my finding while looking for cool technologies out there.

giovedì 24 luglio 2014

Build a simple RESTful Web Service JSON API with Ruby and Sinatra

In one my activities I have the needs to quickly prototype a RESTful web service API.
Obviously I want to do it with my current preferred language Ruby.

It is clear I can easily do it with Rails but probably it will be an overkill for what I need to do.
Reading different articles about major differences between Rails and Sinatra micro-framework I have decided to build the simple REST web service I need using Sinatra.

I am here sharing what I have done. This is something I put together quite quickly, so it is not complete.
Anyone of you which wants to help can contribute.

Let's install the necessary ruby gems.

# cd ~
#
# mkdir rails_api
#
# mkdir rails_api/json
#
# sudo gem install sinatra
#
# sudo gem install rabl
#
# sudo gem install oj
#
# sudo gem install data_mapper
#
# sudo gem install dm-sqlite-adapter
#
# sudo gem install thin

I am using Rabl gem as this provides great flexibility in creating JSON replies to API request

Now in the rails_api/json directory create 3 files with the below content

#post.rabl
object @post
attributes :id, :title, :body

#posts.rabl
collection @posts
attributes :id, :title, :body

#error.rabl
object @error
attributes :message

Those files render the JSON replay to our RESTful API call. Now in the rails_api directory create the following file
#rest_api.rb

require 'rubygems'
require 'sinatra'
require 'rabl'
require 'data_mapper'
require 'json' 

######## setup sqlite DB ########
DataMapper.setup(:default, 'sqlite:rest_api.db')

######## Post Model ########
class Post
  include DataMapper::Resource

  property :id,         Serial    # An auto-increment integer key
  property :title,      String    # A varchar type string, for short strings
  property :body,       Text      # A text block, for longer string data.
end

DataMapper.finalize
Post.auto_upgrade!


######## Very simple Error class ########
class Error 
 attr_accessor :message
 def initialize(mex)
  @message = mex
 end
end

######## register Rabl. This is required for Sinatra ########
Rabl.register!

######## retrun 404 in case of invalid URL request ########
not_found do
 status 404 #page not found
end

######## simple helper to return HTTP 400 ########
def status_400(mex)
 @error = Error.new(mex)
 status 400
 rabl :'error', :format => "json", :views => 'json' 
end

######## simple helper to return HTTP 404 ########
def status_404(mex)
 @error = Error.new(mex)
 status 404
 rabl :'error', :format => "json", :views => 'json' 
end

######## simple helper to return HTTP 200 ########
def status_200
 status 200
end

######## simple helper to return HTTP 201 ########
def status_201(link)
 status 201
 #headers "location:/post/43"
 headers "Location"   => link
end

######## REST CRUD APIs for Post resource ########

######## index of Post ########
#GET post
get '/post' do 
 @posts = Post.all
 if @posts.empty?
  status_404("The reuqested resource does not exists")
 else
  status_200
    rabl :'posts', :format => "json", :views => 'json'
   end
end

######## show one Post ########
# GET /post/:id
get '/post/:id' do
 @post = Post.get(params[:id])
 if @post.nil?
  status_404("The reuqested resource does not exists")
 else
  status_200
    rabl :'post', :format => "json", :views => 'json'
   end
end

######## create a Post ########
#POST /post
post '/post' do
 begin
  post_data =  JSON.parse request.body.read 

  if post_data.nil? or !post_data.has_key?('title') or !post_data.has_key?('body')
   raise "exception"
  else
   post = Post.create(:title => post_data['title'], :body => post_data['body'])
   post.save
   status_201("/post/#{post.id}")
  end
 rescue => ex
  status_400("Invalid client request")
 end
end

######## Update a Post ########
#PUT /post/:id
put '/post/:id' do
 begin
  put_data =  JSON.parse request.body.read 

  if put_data.nil? or !put_data.has_key?('title') or !put_data.has_key?('body')
   raise "exception"
  else
   post = Post.get(params[:id])
   if post.nil?
    status_404("The reuqested resource does not exists")
   else
    post.title = put_data['title']
    post.body = put_data['body']
    post.save
    status_200
   end
  end
 rescue => ex
  status_400("Invalid client request")
 end

end

######## Remove a Post ########
#DELETE /post/:id
delete '/post/:id' do
 post = Post.get(params[:id])
 if post.nil?
  status_404("The reuqested resource does not exists")
 else
  post.destroy
  status_200
 end
end
Ok now just run it with
# ruby rest_api.rb -o 0.0.0.0
You should get something like this
== Sinatra/1.4.5 has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.6.2 codename Doc Brown)
Maximum connections set to 1024
Listening on 0.0.0.0:4567, CTRL+C to stop

Let's now test our RESTful Web Service. You can use your preferred tool like POSTMAN in Chrome.
I will use the always available curl to test the typical CRUD functions

CREATE

# curl -H "Content-type: application/json" -X POST  -d '{"title": "post1", "body": "this is post 1"}'  http://127.0.0.1:4567/post
READ
# curl  http://127.0.0.1:4567/post

# curl  http://127.0.0.1:4567/post/1
UPDATE
# curl -H "Content-type: application/json" -X PUT  -d '{"title": "post 5", "body": "this is post #5"}'  http://127.0.0.1:4567/post/1
DELETE
# curl -X DELETE http://127.0.0.1:4567/post/1

I am sure it is quite easy to argue that the HTTP return code I have used are not correct. Looks like this is quite an open topic.

In my example here I have mapped HTTP Status Code to REST call according to what described in this article (Using HTTP Status Codes correctly in your REST Web API)

As always let me know about any improvement, suggestion or correction.

Hope this helps someone out there.


martedì 15 luglio 2014

rails console and dbconsole on OpenShift

in my rails development environment I can start the console or the DB console by issuing the well know commands:


rails c(onsole)
rails dbconsole

In order to achieve the same result in production environment on OpenShift issue the following:

cd $OPENSHIFT_REPO_DIR

RAILS_ENV=production bundle excec rails c(onsole)

RAILS_ENV=production bundle excec rails dbconsole

lunedì 14 luglio 2014

How to force HTTPS on Openshift for Rails applications

RedHat OpenShift provides the possibility to enable HTTPS for your Rails application.

By default your Rails application will be available on

http://appname-domain.rhcloud.com

and

https://appname-domain.rhcloud.com

In my applications I want every request to be handled by HTTPS. In order to achieve that add to your public directory a .htaccess file with the below content


RewriteEngine on


RewriteCond %{HTTP:X-Forwarded-Proto} !https

RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R,L]


For additional information for non-Apache based applications check OpenShift article out

mercoledì 2 luglio 2014

How to delete a scheduled rails delayed_job

In one of my "experiment" I am using collectiveidea/delayed_job gem to execute background and delayed tasks/jobs.

Now the question is: how to delete a job  which has already been scheduled/queued?

As simple as that:



#schedule a delayed method call
dj = reminder.delay(run_at: 5.minutes.from_now).send #this is your delayed method object

#delete a scheduled delayed job
djid = dj.id #this is the assigned delayed_job id

Delayed::Job.delete(djid)

domenica 22 giugno 2014

Can Digital Platforms impact on social interaction?

Friday afternoon (June 20th) at 6 PM Italy has played and lost against Costa Rica. However this is not the topic of this post. I am not a "real" football fan.

The real topic I want to discuss here, is how technical consideration related to Digital Platform can impact on social interaction.

As we all know today watching TV is more and more a social event.  I was watching the match from Italy, from my home, over a DTT digital platform. My good friend Daniel was watching the same match from a OTT service (UK TVPlayer) from Spain. Both we were able to watch the match with a good quality. So far so good! :)

At the same time we were exchanging comments over mobile app Whatsapp. What we have quickly learned is that we were "out of synch". Any time I was making a comment on a player, on the game, whatever, Daniel was reply with "what are you talking about???"

Yes, Daniel "real time point" was about 2 minutes delayed compared to my DTT "real time point". This means that when Costa Rica scored against Italy :(  Daniel has seen it about 2 minutes later.

Why is this happening? there could be many reasons and if someone knows why this happened I am curious to know. In any case I consider this a very important aspect.

Probably this was not an issue a few World Championship ago. In that case I would have watched the game. Daniel would have watched the game. We would have make comments the day after.

Today this is not the way anymore. We all interact while watching events on TV. And for "live" events like sports the "delay" or other issues, introduced by different digital platform is really impacting how you enjoy the event itself.

This can raise multiple question like is OTT ready for prime time? what operator can do to monetize OTT? The real point I want to make is that when building a modern video service there is more that traditional video quality and other parameters. Today operators must also consider social interaction.

What do you think? Similar experiences? Comments?

NOTE:
In the second half of the game, after the break, the same delay has been reduced to about 20/30 seconds which is much more reasonable and has allowed us a more natural interaction. (Thanks to the TVPlayer guys which fix it during the match break)

venerdì 13 giugno 2014

How to customize cancel button link in Active Admin for Rails

A typical form in Active Admin looks like this one
form do |f|
    f.inputs "New Post" do
      f.input :title,
      f.input :body
    end
    f.actions
end
This will give you the standard buttons: create and cancel Now in my case I need to redirect my user to a specific page when the cancel button is hit This can be achieved in this way:
form do |f|
    f.inputs "New Post" do
      f.input :title,
      f.input :body
    end
    f.actions do
      f.action(:submit) 
      f.cancel_link(admin_anothermodel_path)
    end
end
This is simple and effective way to redirect your user to the location you want