Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FiberError - Fiber called across threads

I'm trying to write a small feature in a Rails app that uses the random-word gem to generate a random noun, then pluralize it. I've been able to get it working the first time I visit the page in development, but I want the script to run again on each page load. Right now, subsequent page loads (until I bounce the server) give me FiberError in WelcomeController#randomwords, fiber called across threads. I attempted to solve this myself, but I'm pretty new to programming and don't really understand how Fibers work. I tried using Queue, but couldn't figure out how to get it to work, again because I don't totally understand the class. How would I go about solving this specific problem?

Source: welcome_helper.rb

def random
  noun = RandomWord.nouns.next.split('_').sample.pluralize
  if noun.include? "_"
    noun = noun.split("_").join.pluralize
  else
    noun.pluralize!
  end      
  return noun
end
like image 620
Alec Wilson Avatar asked Mar 09 '15 20:03

Alec Wilson


1 Answers

The problem, as you might have found out by now, is that the random-word gem is not thread safe. More precisely, RandomWord.nouns is a module-level Enumerator, and accessing enumerators across threads is not safe

However, e.g. Queue is thread safe, so for a thread-safe alternative to this functionality you could take nouns.dat from the random-word gem, and randomly shuffle all its words into a Queue object when you initialize your application. Now, say this queue can be accessed via random_words_queue in the scope of your random method. Then you can implement the random method as

def random
  unless random_words_queue.empty?
    noun = random_words_queue.pop
    if noun.include? "_"
      noun = noun.split("_").join.pluralize
    else
      noun.pluralize!
    end      
    return noun
  end
end

Note that it currently just returns nil if the queue is empty, which you probably don't want. How you want it to behave in this case depends on your requirements:

  • If the words being somewhat predictable is not a security concern, and not likely to annoy your users, then I would just push noun to the back of the queue right after popping it.
  • Otherwise, you should reshuffle the words.

(In any case, returning nil is probably not what anybody wants.)

like image 132
vindvaki Avatar answered Oct 26 '22 21:10

vindvaki