Are Rails Controllers Multithreaded? Thread.Exclusive in Controllers

Are rails controllers multithreaded? Thread.exclusive in controllers

Running rake middleware on a basic rails app gives the following:

use Rack::Lock
use ActionController::Failsafe
use ActionController::Reloader
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActiveRecord::SessionStore, #<Proc:0x017fb394@(eval):8>
use ActionController::RewindableInput
use ActionController::ParamsParser
use Rack::MethodOverride
use Rack::Head
run ActionController::Dispatcher.new

The first item on the rack stack is Rack::Lock. This puts a lock around each request, so only one request is handled at a time. As such a standard rails app is single threaded. You can however spawn new threads within a request that would make your app multi threaded, most people never encounter this.

If you are having issues…

require 'thread'
Thread.exclusive do
# stuff here
end

… would ensure that stuff inside the block is never run in parallel with any other code. Creating a shared Mutext between all threads (in a class variable or something, but this could be wiped when reloaded in dev mode, so be careful), and locking on it as Rack::Lock#call does is to be preferred if you just want to ensure no two instances of the same code is executed at the same time.

Also, for the record, each request creates and dereferences one controller in each request cycle. No two requests should see the same instance, although they may see the same class.

Setting config.threadsafe! voids almost everything I said. That removes Rack::Lock from the stack, and means you will need to set a mutex manually to prevent double entry. Don't do it unless you have a really good reason.

Even without Rack::Lock you will still get one controller instance per request. The entry point to your controller ensures that, notice the call to new in process.

Class methods in Rails, how do they work in terms of performance?

As @Powers alluded to, in Ruby class methods are just instance methods on a class object--performance should be the same as an equivalent instance method. In Rails specifically, many class methods are dynamically generated at runtime (for instance the find_by_* ActiveRecord methods), so performance of class methods can be somewhat unpredictable.

For the question of concurrent access to class methods, most Rails apps are single-threaded and so there will never be concurrent access to the same methods. Scaling to many users in Rails typically involves adding more instances of the Rails app and putting them behind a load balancer, or using a multi-threaded server such as Unicorn (which actually has separate Ruby environments for each thread).

How to Make the Controller wait for a Delayed Job while the rest of the App continues on?

Using DJ to offload the work is absolutely fine and normal, but making the controller wait for the response rather defeats the point.

You can add some form of callback to the end of your check method so that when the job finishes your user can be notified.

You can find some discussion on performing notifications in this question: push-style notifications simliar to Facebook with Rails and jQuery

Alternatively you can have your browser periodically call a controller action that checks for the results of the job - the results would ideally be an ActiveRecord object. Again you can find discussion on periodic javascript in this question: Rails 3 equivalent for periodically_call_remote

Share a Net::IMAP connection between controller actions

How about you create a service object (singleton) that wraps you Net::IMAP. You can stick it in app/services/imap_service.rb or something like that. For an example on what that would look like:

require 'singleton' # This is part of the standard library
require 'connection_pool' # https://github.com/mperham/connection_pool

class IMAPService
include Singleton

def initialize
@imap = ConnectionPool.new(size: 15) { Net::IMAP.new(server, 993, true) }
end

def inbox(user, password)
@imap.with do |conn|
conn.login(user, password)
conn.select("INBOX")
end
end
end

You access this singleton like IMAPService.instance e.g. IMAPService.instance.inbox(user, password). I added in the connect_pool gem as per our discussion to make sure this is thread safe. There is no attr_reader :imap on IMAPService. However, you can add one so that you can directly access the connection pool in your code if you don't want to include all of the necessary methods here (although I recommend using the service object if possible). Then you can do IMAPService.instance.imap.with { |conn| conn.login(user, password) } and don't need to rely on methods in IMAPService.

It's worth noting that you don't have to use the Singleton mixin. There is a really good article on Implementing "the lovely" Singleton which will show you both ways to do it.

How to implement RPC with RabbitMQ in Rails?


Is it possible to avoid creating a queue for every Rails request?

Yes - there is no need for every single request to have it's own reply queue.

You can use the built-in direct-reply queue. See the documentation here.

If you don't want to use the direct-reply feature, you can create a single reply queue per rails instance. You can use a single reply queue, and have the correlation id help you figure out where the reply needs to go within that rails instance.

How will this approach (with threads and mutex) interfere with my whole Rails environment? Is it safe to implement things this way in Rails?

what's the purpose of the lock / mutex in this code? doesn't seem necessary to me, but i'm probably missing something since i haven't done ruby in about 5 years :)

Is it good style to explicitly return in Ruby?

Old (and "answered") question, but I'll toss in my two cents as an answer.

TL;DR - You don't have to, but it can make your code a lot more clear in some cases.

Though not using an explicit return may be "the Ruby way", it's confusing to programmers working with unfamiliar code, or unfamiliar with this feature of Ruby.

It's a somewhat contrived example, but imagine having a little function like this, which adds one to the number passed, and assigns it to an instance variable.

def plus_one_to_y(x)
@y = x + 1
end

Was this meant to be a function that returned a value, or not? It's really hard to say what the developer meant, as it both assigns the instance variable, AND returns the value assigned as well.

Suppose much later, another programmer (perhaps not that familiar with how Ruby does returns based on last line of code executed) comes along and wants to put in some print statements for logging, and the function becomes this...

def plus_one_to_y(x)
@y = x + 1
puts "In plus_one_to_y"
end

Now the function is broken if anything expects a returned value. If nothing expects a returned value, it's fine. Clearly if somewhere further down the code chain, something calling this is expecting a returned value, it's going to fail as it's not getting back what it expects.

The real question now is this: did anything really expect a returned value? Did this break something or not? Will it break something in the future? Who knows! Only a full code review of all calls will let you know.

So for me at least, the best practice approach is to either be very explicit that you are returning something if it matters, or return nothing at all when it doesn't.

So in the case of our little demo function, assuming we wanted it to return a value, it would be written like this...

def plus_one_to_y(x)
@y = x + 1
puts "In plus_one_to_y"
return @y
end

And it would be very clear to any programmer that it does return a value, and much harder for them to break it without realizing it.

Alternatively, one could write it like this and leave out the return statement...

def plus_one_to_y(x)
@y = x + 1
puts "In plus_one_to_y"
@y
end

But why bother leaving out the word return? Why not just put it in there and make it 100% clear what's happening? It will literally have no impact on your code's ability to perform.

Concurrent cause duplicate records inserted

The root cause may be a race condition in the app. Rails validates_uniqueness_of doesn't really work fully, because it can't guarantee uniqueness at the database level when you've got race conditions such as multiple threads, multiple web requests, etc.

http://1rad.wordpress.com/2008/09/29/0x04-atomic-science/

In your particular case, the sequential id numbers could be caused by, for example, a user double-clicking a "Save" button that triggers two Ajax requests (instead of just one), and a Rails controller that does a model find_or_create.

Your database isolation of REPEATABLE-READ doesn't matter for the race condition. REPEATABLE-READ means every lock acquired during a transaction is held for the duration of the transaction; you can still have phantom reads. What the Rails tutorial was trying to explain is that the validates_uniqueness_of race condition happens even if you're using SERIALIZABLE, which prevents phantom reads and is thus more protected than REPEATABLE-READ.

To fix this in your app, stop relying exclusively on validates_uniqueness_of in Rails, and start using uniqueness guarantees that are built into the database, such as a unique primary key, or your solution of a unique composite index. This ensures that even when you have a race in Rails, your database will block the race.

Eliminating the race in Rails (not the DB) can be accomplished, but it's probably not a smart approach for a typical Rails web app. For example, you could eliminate the race in Rails by using a web server that allows only one request at a time, and only one Rails app connects to the database at a time.

If you discover that your race is caused by something like an Ajax button double-click, you can be very helpful to your user by putting some smarts into the button, so it doesn't send the same data twice in quick succession. This will eliminate an Ajax race for many common use cases.

Why would multiple simultaneous AJAX calls to the same ASP.NET MVC action cause the browser to block?

The answer was staring me in the face.

ASP.NET Session State Overview:

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished.

Annoyingly I'd skimmed paragraph this a couple of weeks ago not really taking in the full impact of the bold sentences. I had read that simply as "access to session state is serialised" and not "all requests, no matter whether you touch session state or not, are serialised" if the requests came from the same session.

Fortunately there is a work around in ASP.NET MVC3 and its possible to create session-less controllers. Scott Guthrie talks about these here:

Announcing ASP.NET MVC 3 (Release Candidate 2)

I installed MVC3 RC2 and upgraded the project. Decorating the controller in question with [SessionState(SessionStateBehavior.Disabled)] solves the problem.

And of course typically I just found this in Stack Overflow a few minutes ago:

Asynchronous Controller is blocking requests in ASP.NET MVC through jQuery

how multiple threads invoke singleton object's method and work on them?

I think you have to distinguish between what you've already stored in memory and code execution.

In a Singleton Object you have:

  • Fields: They are stored in memory. They can be shared amongst multiple threads and you have no guarantee they will keep consistent (unless you make them synchronized).
  • Methods to be called: They can be called from more than one thread. Each execution is independent and thread safe, unless they access some shared field improperly.

Now coming to your question: if you share your singleton object among multiple threads and access it concurrently, every single thread will execute Singleton object's portion of code, wrapped in its own execution.

Also if you write a Thread.currentThread().getId(); which basically returns the thread ID you're executing into singleton's methods, you will obtain different ids, because different threads are executing their own method stack. Being stateless means you've no fields into the singleton to be shared amongst them!

A word on Stateless and Stateful

Stateless means that the bean hasn't got any modifiable field to share. That means you have only methods or/and static stuff in your object, so you can use them anywhere and will always return you same result. You don't have to worry about synchronizing the access to the field.

That's a basic example about stateless, let's suppose you have a class that only performs the sum operation:

public class StatelessClass{

public int sum(int a, int b){
return a+b;
}

}

In the same way, you can declare it as a abstract class (no instantiable itself) and make its methods static, which means you don't need any instance of it to call its methods:

public abstract class StatelessClass{

/**
* I only sum objects
*/
public static int sum(int a, int b){
return a+b;
}

}

Then you can use it as StatelessClass.sum(1,1);, this actually would be very similar to have a Singleton object itself, with the difference that in the Singleton you have a unique instance shared in the application.

In the same way, having a field which is injected and provides access to a service neither is considered to alter the state of the object:

public class StatelessServiceClass{

private Service service;

public int sum(int a, int b){
return service.sum(a,b);
}

public void setService(Service serv){
this.service=serv;
}

}

However, having a field which is modifiable makes the Object stateful:

public class StatefulClass{

//This fields make the object STATEFUL
private int totalSum = 0;

public int sum(int a, int b){
int sum = a + b;
totalSum = totalSum + sum;
if (totalSum > 100)
System.out.println("This thread "+Thread.currentThread().getId()+
+" got it!");
return sum;
}

}

As sum can be accessed by multiple threads at the same time, you should guarantee that totalSum is accessed in a synchronized way. The printed sentence is not guaranteed to be true unless you do it.

All of this is also properly explained in this answer's Threadsafety piece by @BalusC.



Related Topics



Leave a reply



Submit