Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I want to be able to call a method that repeats x amount of times on a separate thread that sends messages such as "still running" every few moments to the console while I am free to call other methods that do the same thing.

This works in my test environment and everything checks out via rspec - but when I move the code into a gem and call it from another script, it appears that the code is working in additional threads, but the strings are never sent to my console (or anywhere that I can tell).

I will put the important parts of the code below, but for a better understanding it is important to know that:

  1. The code will check stock market prices at set intervals with the intent of notifying the user when the value of said stock reaches a specific price.
  2. The code should print to the console a message stating that the code is still running when the price has not been met.
  3. The code should tell the user that the stock has met the target price and then stop looping.

Here is the code:

require "trade_watcher/version"
require "market_beat"

module TradeWatcher


  def self.check_stock_every_x_seconds_for_value(symbol, seconds, value)
    t1 = Thread.new{(self.checker(symbol, seconds, value))} 
  end

  private
      def self.checker(symbol, seconds, value)
        stop_time = get_stop_time
        pp stop_time
        until is_stock_at_or_above_value(symbol, value) || Time.now >= stop_time
          pp "#{Time.now} #{symbol} has not yet met your target of #{value}."
          sleep(seconds)
        end
        if Time.now >= stop_time
          out_of_time(symbol, value)
        else
          reached_target(symbol, value)
        end
      end

      def self.get_stop_time
        Time.now + 3600 # an hour from Time.now
      end

      def self.reached_target(symbol, value)
        pp "#{Time.now} #{symbol} has met or exceeded your target of #{value}."
      end

      def self.out_of_time(symbol, value)
        pp "#{Time.now} The monitoring of #{symbol} with a target of #{value} has expired due to the time limit of 1 hour being rached."
      end

      def self.last_trade(symbol)
        MarketBeat.last_trade_real_time symbol
      end

      def self.is_stock_at_or_above_value(symbol, value)
        last_trade(symbol).to_f >= value
      end
end

Here are the tests (that all pass):

require 'spec_helper'

describe  "TradeWatcher" do
  context "when comparing quotes to targets values" do
    it "can report true if a quote is above a target value" do
      TradeWatcher.stub!(:last_trade).and_return(901)
      TradeWatcher.is_stock_at_or_above_value(:AAPL, 900).should == true
    end

    it "can report false if a quote is below a target value" do
      TradeWatcher.stub!(:last_trade).and_return(901)
      TradeWatcher.is_stock_at_or_above_value(:AAPL, 1000).should == false
    end
  end

  it "checks stock value multiple times while stock is not at or above the target value" do
    TradeWatcher.stub!(:last_trade).and_return(200)
    TradeWatcher.should_receive(:is_stock_at_or_above_value).at_least(2).times
    TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 400.01)
    sleep(2)
  end

  it "triggers target_value_reahed when the stock has met or surpassed the target value" do
    TradeWatcher.stub!(:last_trade).and_return(200)
    TradeWatcher.should_receive(:reached_target).exactly(1).times
    TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 100.01)
    sleep(2)
  end

  it "returns a 'time limit reached' message once a stock has been monitored for the maximum of 1 hour" do
    TradeWatcher.stub!(:last_trade).and_return(200)
    TradeWatcher.stub!(:get_stop_time).and_return(Time.now - 3700)
    TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 100.01)
    TradeWatcher.should_receive(:out_of_time).exactly(1).times
    sleep(2)
  end

end

And here is a very simple script that (in my understanding) should print "{Time.now} AAPL has not yet met your target of 800.54." every 1 second that the method is still running and should at least be visible for 20 seconds (I test this using sleep in rspec and am able to see the strings printed to the console):

require 'trade_watcher'
TradeWatcher.check_stock_every_x_seconds_for_value(:AAPL, 1, 800.54)
sleep (20)

However I get no output - although the program does wait 20 seconds to finish. If I add other lines to print out to the console they work just fine, but nothing within the thread triggered by my TradeWatcher method call actually work.

In short, I'm not understanding how to have threads communicate with each other appropriately - or how to sync them up with each other (I don't think thread.join is appropriate here because it would leave the main thread hanging and unable to accept another method call if I chose to send one at a time in the future). My understanding of Ruby multithreading is weak anyone able to understand what I'm trying to get at here and nudge me in the right direction?

share|improve this question
I've moved this to Stack Overflow because Code Review isn't the correct place to ask "How do I" questions. – sepp2k Apr 21 at 9:54

migrated from codereview.stackexchange.com Apr 21 at 9:54

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.