Sidekiq configuration for SOA / multiple environments on same server

The Sidekiq configuration file by default located at config/sidekiq.yml. It is only necessary to create the file if you need to set advanced options, such as concurrency pool size, named queues, PID file location, etc.
Here is an example configuration file:


:concurrency: 5
:pidfile: tmp/pids/sidekiq.pid
staging:
:concurrency: 10
production:
:concurrency: 50
:queues:
- default

By default, one Sidekiq process will be started on each app server.

Setting the Location of your Redis server

By default, Redis is located at localhost:6379.

Following is my development environment,
SOA + Ruby(2.0) + Rails(4.0) + Unicorn  + Nginx  + SideKiq + MultiTenant

In your config/initializers/sidekiq.rb file,

Sidekiq.configure_server do |config|
config.redis = { url: ‘redis://localhost:6379/0′, namespace: “sidekiq_app_name_#{Rails.env}” }
end

Sidekiq.configure_client do |config|
config.redis = { url: ‘redis://localhost:6379/0′, namespace: “sidekiq_app_name_#{Rails.env}” }
end

Usage:
The :namespace parameter is recommended if Sidekiq is sharing access to a Redis database.

Finally, start sidekiq from the root directory of your Rails app.

bundle exec sidekiq -e staging -C config/sidekiq.yml

Categories: Rails, Ruby Tags: , , , ,

MySQL Master-Slave Replication

The advantages of replication:-
1) Offload some queries from one server to other.
2) Use master for all writes and Use slave for all reads.

Some basic stuff to remember before we go ahead:-
1. Master and slave installations will be on different server instances.
2. The master should not be in use during the installation process (if master is already present).

1) Setup Master server:-

   install MySQL Server
   sudo apt-get install mysql-server

after installation, Configure it to make this as Master server.

Edit

   /etc/mysql/my.cnf

MySQL should listen to all IP Addresses, so we comment out the following lines:

   #skip-networking
   #bind-address = 127.0.0.1

Set unique server ID

   server-id=1

Enable binary logging

   log-bin = /var/log/mysql/mysql-bin.log

Restart MySQL by using the command

   sudo service mysql restart

Log in to the MySQL shell

   mysql -u root -p

Create a replication user:
Its recommended to create a separate user for mysql replication to which slaves can authenticate.  Slaves will be connecting to the master using this user’s credentials.

   GRANT REPLICATION SLAVE ON *.* TO 'slaveuser'@'%' IDENTIFIED BY   
 '<a_real_password>';
   FLUSH PRIVILEGES;
   FLUSH TABLES WITH READ LOCK;
   SHOW MASTER STATUS;

After running the above command, you should be able to see binary log position

  +------------------+----------+--------------+------------------+
   | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
   +------------------+----------+--------------+------------------+
   | mysql-bin.000001 |      107 |              |                  |
   +------------------+----------+--------------+------------------+

Write down the position, this would be needed later.

Note: If you already have a master setup with data, dump the data so that it can be imported to the slave for the data to be in sync.

Leave the shell.

   quit;

2) Setup Slave server:-

   install MySQL Server
   sudo apt-get install mysql-server

after installation, Configure it to make this as slave server.

Edit

   /etc/mysql/my.cnf

Set unique server ID

   Server-id=2

Restart MySQL by using the command

   sudo service mysql restart

Use below command to load the initial data from master

   mysql -u root -p<password> database_name < /path/to/masterdump.sql

Log in to the MySQL shell

   mysql -u root -p

We need to inform our slave server the details of master server like host name, replication username and password, etc. Other things that slave server need is master log file name and log position, which we have obtained by entering show master status on master server. Now we can connect slave with the master by issuing the following command

   CHANGE MASTER TO MASTER_HOST = '<host_name>', MASTER_USER ='slaveuser', 
 MASTER_PASSWORD='<a_real_password>', MASTER_LOG_FILE = 'mysql-bin.000001', 
MASTER_LOG_POS =107;

Finally, start the slave

   START SLAVE;
   SHOW SLAVE STATUS\G; 
   quit;

Now in the master host run the following command to release the lock

   mysql> UNLOCK TABLES;

And now, each write to the master gets instantly replicated on the slave as well.

Categories: Database Tags: ,

How to make your application work for both MySQL and PostgreSQL?

I am using rails 3 and ruby 1.9.2 in my application.
For development environment, I am using MySQL and for staging environment, I am using PostgreSQL Database.
After hosting, we have faced some issues.

1) Quoting styles:
MySQL allows you to quote table and column names with backquotes, whereas PostgreSQL uses double quotes.
For ex:
One of our tables has a column in it called when, which must be quoted whenever we use it.
Rails will of course handle the quoting for you if you do something like

Meeting.find_by_when(Time.now)

But if you are constructing your own SQL conditions then you have to handle the quoting problem.

In MySQL, it would be like

Meeting.where("`when` < ?", Time.now)

In PostgreSQL, it would be like

Meeting.where("\"when\" < ?", Time.now)

Solution:

Meeting.where("#{Meeting.connection.quote_column_name(when)} < ?", Time.now)

2) Boolean type:
MySQL lacks a native BOOLEAN type, so if you create a boolean column in Rails, you will end up with a TINYINT(1) column which has values of 0 and 1 for false and true respectively. PostgreSQL has a native BOOLEAN type, it will accept only false/true unlike MySQL.

In MySQL, it would be like

Meeting.where("import=1") OR Meeting.where("import=?", true)

In PostgreSQL, it would be like

Meeting.where("import=?", true)

Solution:

so replace 0 and 1 with false and true in your all files then it work in both 
MySQL and PostgreSQL.


3) Other differences:
(i) Fulltext Search: PostgreSQL is case sensitive. MySQL is not case sensitive.
(ii) To select random records from DB, Mysql has a function called “rand()” and PostgreSQL has a function called “random()”.
(iii) PostgreSQL ALTER TABLE supports ADD COLUMN, RENAME COLUMN and RENAME TABLE only. MySQL has all options in ALTER TABLE.
(iv) In PostgreSQL, attribute name starting with numbers, like “360_degree” are not allowed.

Good luck!

Categories: Database Tags: , ,

Incompatible character encodings error in ruby 1.9

Problem:
Incompatible character encodings error while importing csv files in ruby 1.9 which have data in multiple languages.

I am using rails 3 and ruby 1.9.2 in my application.
While importing/parsing the CSV, I get an error “Incompatible character encodings: ASCII-8bit and UTF-8″. I quickly checked my database encoding, it was UTF-8 only and also in application.rb, I had

'config.encoding = "utf-8"'.

I had no idea what was going wrong…

After googling a bit, I found that couple of posts mentioned some workarounds for this issue, so I tried:

# encoding: utf-8 => in my class
and
"hello ümlaut".force_encoding("UTF-8")

That output was

"hello ?mlat" 

With this the Error was fixed (no rails error) but the converted string value is incorrect. It was working correctly in some places but not everywhere.

I searched a bit more and then I found that the sequence of bytes that represent an “ü” is different in different encodings and could not be recognized in UTF-8, so such characters were replaced with a “?”.

Solution:
We have to find out that the original encoding of the string and then convert to UTF-8. To achieve this in ruby 1.9.2, we can’t do it directly.
so, we need to install the gem ‘rchardet19′
and then add this to the top of your class, require ‘iconv’

now,

  data = CharDet.detect(value)
  puts "Detected encoding- #{data.encoding}"

and,

  value = (data.confidence > 0.6 ? Iconv.iconv("UTF-8", data.encoding, value)
           : value)

we are just converting to UTF-8 from the detected encoding.

This fixes the issue.

Categories: Ruby Tags: , ,

Tips for faster loading web sites(Optimizing page load time)

1) Make fewer HTTP request(Js, CSS & image)
     Most of the end-user response time is spent on the front-end and tied up in downloading all the components in the page like images, stylesheets, scripts, etc. Reducing the number of components in turn reduces the number of HTTP requests.
     a) Combined files => its a way to reduce the number of HTTP requests by combining all files into a single file. ex: js & css
         In our rails app, we used bundle_fu(https://github.com/timcharper/bundle-fu). Its used to bundle all your assets very easy. It can speed your load time up around 50%.

         Example put the following around your stylesheets/javascripts:
         -bundle :name => "default_bundle" do
           = javascript_include_tag "http://w.sharethis.com/button/buttons.js"
           = stylesheet_link_tag 'jquery-ui', 'auto_complete/token-input.css'
           = javascript_include_tag 'jquery-1.4.2.js', 'jquery-ui.js', 'auto_complete/jquery.tokeninput.js', 'auto_complete/setup.js', 'underscore.js', 'date.js', 'cal.js', 'application.js', 'time_picker/jquery.timePicker.js', 'ajax_pagination.js'
           = stylesheet_link_tag 'compiled/certification.css','compiled/error.css', 'compiled/elements.css', 'compiled/messages.css', 'compiled/calendar.css', 'compiled/common.css', 'time_picker/timePicker.css', :media => 'screen, projection'
           = stylesheet_link_tag 'compiled/print.css', :media => 'print'
           = javascript_include_tag "markerCluster/jsapi", "markerCluster/map.js", "markerCluster/markerclusterer.js", "jquery-jtemplates"

     b) CSS sprites     => Its used to reducing the number of image requests. Combine your background images into a single image and use the CSS background-image and background-position properties to display the desired image segment.

2) Avoid empty src or href
     You may expect a browser to do nothing. But most browsers makes a request to server(sending a large amount of unexpected traffic).

3) Compress components with gzip
     This is used to reduce their file size over the wire by approximately 70%. This can be set up using your Apache(needs Apache 2, mod_deflate, mod_headers and access to server config) or Nginx config.

     example for apache(in the server config file):
     # Compress some text file types
     AddOutputFilterByType DEFLATE text/html text/css text/xml application/x-javascript
            
     # Deactivate compression for buggy browsers
     BrowserMatch ^Mozilla/4 gzip-only-text/html
     BrowserMatch ^Mozilla/4\.0[678] no-gzip
     BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
            
     # Set header information for proxies
     Header append Vary User-Agent

4) Add expires headers for JS & CSS
     There are two aspects to this rule:
     a) For static components : implement "Never expire" policy by setting far future Expires header
     b) For dynamic components: use an appropriate Cache-Control header to help the browser with conditional requests
        
     This means that A first-time visitor to your page may have to make several HTTP requests, but by using the Expires header you make those components cacheable. The next request, Browser use a cache to reduce the number and size of HTTP requests, making web pages load faster. A web server uses the Expires header in the HTTP response to tell the client how long a component can be cached. However, it creates an additional problem too. The problem is what happens if you change these files? The browser will be stuck with the old files. The solution is to send a last modified timestamp with your requests (Ex: "<img src='/images/rails.png?84392578943' />"). Now your browser will know to ask for the file again. The "timestamp" is the default behavior of rails.

5) Put CSS at top
     Yahoo discovered that moving stylesheets to the document HEAD makes pages appear to be loading faster. This is because putting stylesheets in the HEAD allows the page to render progressively.

6) Minify JS & CSS
     Minification is the practice of removing unnecessary characters from code like comments and unneeded white space characters (space, newline, tab and etc). This improves response time performance & load times. You can use JSMin and YUI Compressor for minifying your JS code. Also some plugins are there, please check it here: https://github.com/sinefunc/sinatra-minify and https://github.com/ericbarnes/ci-minify.

please check the screenshot. Right now, as you can see, I have made it Yslow grade from "F" to "B" very easily. I am sure, we can easily get grade "A" too... We need some support from the server side regarding "Add expires header" and "Use Cookie-free Domains for Components". I have requested engineyard(hosting server) for the same. Waiting for the reply from them. By next week, it will turn into grade "A".

and also found one good link from rubyquicktips. Benchmark.ms is very nice. its used to track how long some bit of code takes to process. please check it here: http://rubyquicktips.tumblr.com/post/2838217166/benchmark-ms-rails-you-sneaky-devil

Before optimization:


After optimization:


Categories: Rails Tags: ,

“cycle” helper in Rails

If you wanna display the list of records with different(alternate) classes for table rows, then you can use this helper(you no need to check odd-even records). Rails has so many awesome feature like this.

for ex: if you want to apply ‘odd’ and ‘even’ class for alternate record

 -season_hash.each do |k, v|
   %tr{:class => "#{cycle('odd', 'even')}"}
     %td= v["games"]
     %td= v["goals"]
     %td= v["assists"]
     %td= v["practices"]

Categories: Rails Tags:

“ordinalize” in Rails

How to display a date with suffix like “th”, “st”, “nd”, or “rd”?

for example, I wanna display like this Mon, 7th April

Rails has inbuilt function – “ordinalize”

It turns a number into an ordinal string used to denote the position in an ordered sequence such as 1st, 2nd, 3rd, 4th

date.strftime(“%a, #{date.day.ordinalize} %B”)

Categories: Rails Tags:
Follow

Get every new post delivered to your Inbox.

Join 100 other followers