What is config.threadsafe!

Web Developer, Ruby on Rails and JavaScript enthusiast

ct

We all love Rails for it’s elegance and immense support of features that it provides to accomplish our tasks. Rails is feature rich and truly allows the developer to focus on the application instead repetitive tasks such as querying the database, manage routing, combining templates etc.

In the process of providing the developer with the ease of developing web applications, Rails often hides many details from developers. It does this deliberately because Rails doesn’t want to burden developers with what is going on under-the-hood while he/she building something useful. Developers can read the Rails source whenever they want, though, and most do once the application starts to get large.

Beginners and intermediate developers often find it difficult to get a sense of some important concepts in Rails, such as Rack, Rack Middleware, ActiveRecord, Asset Pipeline, thread safety etc. In this post, I will focus on thread safety in Rails.

Let’s first talk about multithreading. Mutltithreading is a very vital concept in Computer Science and we cannot underestimate importance of threads today. Threads are everywhere, used to perform very important work. According to Wikipedia:

In computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by an operating system scheduler. A thread is a light-weight process.

As Wikipedia said, a thread is a light-weight process. Threads that belongs to the same process share that process’s resources. That’s why it is more economical to have threads than processes in terms of memory. In web environments, threads are often used to handle some background job or a long running task asynchronously. But we have to be really careful when dealing with threads, or else we may experience unexpected results due to a concept called race conditions that occur in multithreaded systems. According to Wikipedia:

Race conditions arise in software when separate computer processes or threads of execution depend on some shared state. Operations upon shared states are critical sections that must be mutually exclusive. Failure to obey this rule opens up the possibility of corrupting the shared state.

We have reviewed some useful concepts in Computer Science, now let’s introduce thread safety in Rails. Thread safety in Rails is not new, indeed it dates back to Rails 2.3.*. Josh Peek has done incredible work to make Rails thread safe. Thread safety in Rails avoids the aforementioned race conditions.

It means that, in a multithreaded web-server environment, our code should be thread safe. If multiple threads are accessing our web application then our shared data should not be corrupted when all threads finish processing.

But Rails can’t guarantee this because developers can make mistakes that result in non-thread safe code. So, how does Rails provide us with the guarantee of thread safe code?

Rails, by default, adds a middleware called “Rack::Lock” to our middleware stack. This middleware is the second middleware in the default stack. To find out what middleware is included in a Rails app, simply type rake middleware in your app directory.

The first middleware, ActionDispatch::Static, is used to serve static assets such as JavaScript, CSS files and images.

Rack::Lock guarantees that only one thread will be executing at a given time. If we remove this middleware then multiple threads can be executed at single time. MRI Ruby has a mechanism called the GIL (Global Interpreter Lock) or GVL (Global VM Lock / Giant VM Lock) as of Ruby 1.9. The GIL guarantees that only one thread will be executing at any given time and, in case of multithreading Ruby, it performs context switching. Ruby is intelligent enough to start processing another thread if some executing thread is waiting for an operation to complete.

Let’s have a practical example of Rails threadsafety in action.

Create a sample Rails app.

rails new test_app

Now cd into newly created Rails project and bundle to install the necessary gems.

bundle install

After this, create a controller with some basic actions.

rails generate controller thread_safety index simple infinite

This will create a controller called ThreadSafetyController with index, simple and infinite actions. Open up app/views/thread_safety/index.html.erb and paste in the following code:

<button id="simple_request">Simple Request</button>
&nbsp;
<button id="infinite_request">Infinite Request</button>

<script type="text/javascript">
    $("#simple_request").click(function() {
        $.get("/users/simple", function(data) {
            alert(data)
        });
    });

    $("#infinite_request").click(function() {
        $.get("/users/infinite", function(data) {
            alert(data)
        });
    });
</script>

This will create a page with two buttons on it. The purpose of two buttons is to send Ajax requests to their corresponding actions and display returned data in an alert box.

Let’s add some server-side code in app/controllers/thread_safety_controller.rb

def simple
  sleep(1)
  render :text => "Welcome from simple method"
end

def infinite
  while true
  end
end

The above code is quite simple. simple is sleeping for 1 second and then rendering a simple text/plain response to client. While the infinite method is an infinite loop and will never return anything. Start a server by typing rails s and navigate to http://localhost:3000/thread_safety/index

Click on the “Simple” button and, after one second, you will get a response in an alert box sent from the server. Now,click the “Infinite” button and wait for a response.

The infinite method will never return because of a deliberate infinite loop. Press the “Simple” button again. If you expect to see same response from the server that we got earlier, then you are wrong :-).

This is thread safety. Rails guarantees our code to be thread safe by only allowing one thread to execute at a time. No other thread(s) can execute unless the executing thread finishes it’s processing. Since the infinite thread will never finish because of an infinite loop no other threads will get a chance to process.

Even if we run our application in production environment we will get the same result. This is cool because only one thread is getting executed and we can guarantee that our Rails code is threadsafe. But there is a problem.

If you have deployed this application to a production environment using WEBrick (which you shouldn’t) then your users might experience poor performance because only one thread will be executing at any give time. If some thread takes longer than usual executing other threads will have to wait. This will annoy the users.

Our assets will not face this problem because, once the response is sent back to client, our server can serve static assets to multiple clients at once. This is due to static assets being handled by ActionDispatch::Static which is the first middleware in the stack.

How can we process multiple requests without blocking other requests? We can simply disable thread safety by enabling config.threadsafe! in the development.rb or production.rb file. When we enable this option, there is a massive change in our application.

Now, you can click the “Simple” button multiple times after clicking the “Infinite” button and it will return a response from the server. We have enable multithreading in our Rails App, but it’s our responsibility to now write thread safe code. For more, in-depth information on config.threadsafe! please read this awesome article by Aaron Patterson.

We have successfully demonstrated the concept of thread safety in Rails. Let me share some good news with you. You can use a process-based web server to process multiple requests, even with the config.threadsafe! option disabled. If we run our app on servers such as Unicorn or Apache Passenger / Nginx Passenger, simple Ajax requests will always get returned successfully even if we have triggered infinite Ajax request.

This is because a process-based web server creates worker processes and each process holds one instance of our application. Apache Passenger spawns a child process for each request it handles. So, when we issue the infinite Ajax request, one worker thread starts handling that request and when we instantiate simple Ajax request it gets handled by a newly spawned child. Aaron Patterson mentions in his article that config.threadsafe! has no effect in process-based servers.

I hope you learned something about Rails and thread safety today. Thanks for reading!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Irfan Zaheer

    Perfect Article!

  • Muhammad Irfan

    nice one!

  • Muhammad Akmal

    very nice

  • Anonymous

    You have error in your AJAX calls. You are calling wrong route (for ex. /users/simple instead of /thread_safety/simple).
    This article shows that people often doesn’t try code but prefer just to read :)

  • Rodrigo Rosenfeld Rosas

    I would be careful before advising people to use Rails in threaded model. Rails core doesn’t seem to give good enough support for thread-safety reported bugs:

    https://groups.google.com/forum/#!topic/rubyonrails-core/9XgAybe945k

    • Imran Latif

      @Rodrigo: Thanks for your comment. This article is about how Rails behaves differently in multithreaded webserver environment and in process-based webserver environment. I left it to readers to choose their favorite webserver model to run Rails :-).

  • John Unruh

    Thank you for explaining some of the issues related to threads. This article actually describes the starvation problem, where one thread consumes so many resources (in this case 100% of available processor) that other threads cannot do anything useful. Race conditions, where the order of execution can cause incorrect results, and deadlocks, where two or more threads (or processes) are each waiting for a lock held by the other(s) are other problems that can occur in concurrent systems.

    The process model does provide isolation that can eliminate problems when the software does not need to share state, but sometimes at the cost of more overhead. On the other hand, people working on real time control systems have been in multi-threaded environments for many, many years and generally produce software of acceptable quality, so threading has not proved to be a huge problem when the programmers understand the environment and technology and exercise reasonable care.