2

I am an absolute newbie without even a computer science background. I am just a mechanical engineer trying to implement a way to remotely monitor the power output (and other output data) of the inverters in the solar power systems we install. So if I say anything exceedingly dumb, I apologize in advance.

I'm trying to write a little ruby program that will live in my ror website's database folder. Every 15 minutes (for as long as the system is online producing energy), I want it to poll the data from our customers' inverters (via TCPSocket connection to a gateway connected to customer inverter) and update my website's database file with the new data. The loop I have looks something like this:

last_min = Time.new.min

while(1) do

tsec = Time.new.sec
tmin = Time.new.min

  if ( ( tsec == 0 ) && ( tmin - last_min == 1 ) )    # test using one minute
     # poll inverters, update database
     last_min = tmin
  end

end

When I ran it at first, it threw a Segmentation Fault error. Then i put GC.disable up top and it worked fine (until I force quit only after a couple of min), but that was just to see if it was a garbage collection issue which it is and it seems to be the first creation of a time object that triggers the issue (throws the segmentation fault error). I know I obviously can't have garbage collection disabled for an infinite loop. But how do I "clean up after myself" with ruby? Can I free those time objects somehow at the end of every run through the loop? I saw a post about GC.start, but couldn't quite understand how that works.

Also is there a way to run my program and see how much RAM it's using as it goes? I would appreciate any and all advice anyone could offer me here. (Including advice about the general architecture of the solar power output monitoring system I described in the beginning!)

I have already deeply benefited from looking at all of the posts on here in my journey thus far and I thank you in advance!

edgerunner
  • 14,873
  • 2
  • 57
  • 69
pitachip
  • 965
  • 3
  • 7
  • 24

2 Answers2

3

To force the garbage collection, just call GC.start at the end of your loop. Anything that can be garbage collected will be garbage collected.

With that said, if you really just want an infinite loop to do something every minute (or 15 minutes), instead of comparing Time.now minutes and seconds, just make a call to sleep inside of your infinite loop.

loop do
  poll_inverters_and_update_db
  sleep 60
end

Since you mentioned you are using Rails, you may also want to look into delayed_job for doing this type of thing, or just setting up a cron job to execute every n minutes.

Aaron Hinni
  • 14,578
  • 6
  • 39
  • 39
  • Yes, use sleep, otherwise the loop takes 100% CPU. – steenslag May 11 '11 at 20:41
  • My only problem with sleep() is I actually want the data polled every 15 min on the 15 so customers can be all "Oh my system was producing 3.8 kW at 11:15am" And with the not exactly 24 hr lengths of days and leap years...you know. It looks like I should look into this delayed_job or cron job method (I have no idea what either are). Which of these two methods do you think would be better for this job? – pitachip May 11 '11 at 21:09
  • 1
    If you want something to happen every 15 minutes on the 15, then the easiest thing to do would be to configure a cron job. */15 * * * * /path/to/your/script is the likely syntax for your crontab. Where your script will simply do the `poll_inverters_and_update_db`. – Aaron Hinni May 12 '11 at 02:07
  • Also, if you script is going to depend on code in your rails app (sharing a database etc), then you'll want to look into running the script with rake or similar: http://stackoverflow.com/questions/591503/rails-task-script-runner-or-rake – Aaron Hinni May 12 '11 at 02:09
0

Sounds like an interesting project.

You only need one Time object per interval, since you can do arithmetic operations with times. For example:

t0 = Time.new

while(1) do

  if ( Time.new - t0 >= 60 )    # test using one minute
     # poll inverters, update database
     t0 = Time.new
  end

end

Then you don't need to worry about GC issues.

PS. +1 for using delayed_job or some other way of putting this in its own thread, or cron if you can run it as its own process, since a loop like this or using sleep() will block everything else.

Eric G
  • 1,282
  • 8
  • 18
  • i just found a nice ruby gem called "whenever" to help me set up a cron job. Thanks so much for pointing me in the right direction! I'll let you know how it goes! – pitachip May 11 '11 at 21:20