looper 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.textile +46 -0
  2. data/lib/looper.rb +71 -0
  3. data/looper.gemspec +18 -0
  4. metadata +56 -0
@@ -0,0 +1,46 @@
1
+ Looper is a dead simple Ruby module for daemonizing your code, meant for use with Rails' script/runner. No forking involved, no detaching, simply running a nice healthy loop, but allowing your code to bail out of it, and making it responsive to signals.
2
+
3
+ You implement a class like "DoSomething" that checks for new message objects and then does something to them. This class will include @Looper@ in order to easily loop, respond to shutdown signals, and it can then be run via script/runner as a daemon.
4
+
5
+ The loop handles sleeping between runs, and will catch any unhandled exceptions that bubble up and keep on truckin'. Thus, if you want to exit on a particular exception, you've got to rescue it in your code and set @@run@ to @false@.
6
+
7
+ Here's an example usage:
8
+
9
+ <pre>
10
+ require 'looper'
11
+
12
+ class DoSomething
13
+ include Looper
14
+
15
+ attr_accessor :run
16
+
17
+ def initialize(config)
18
+ @run = true
19
+ # do config stuff, etc...
20
+ @sleep = config[:sleep].nil? ? 60 : config[:sleep]
21
+ end # initialize
22
+
23
+ def run
24
+ loopme(@sleep) do
25
+ begin
26
+ # this is where the meat of your code goes...
27
+ messages = twitter.direct_messages({:since => since.strftime("%a, %d %b %Y %H:%M:%S %Z")})
28
+ rescue Twitter::EpicFailure => e
29
+ puts "bailing out, dude!"
30
+ # set run to false to put the kabosh on the next run
31
+ @run = false
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # and here's how we kick it off:
38
+ DoSomething.new( { :sleep => 10 } ).run
39
+
40
+ </pre>
41
+
42
+ Now we can just kick that off any way we like and background the process, but we tend to use it with script/runner in our Rails environments to have access to our models and such. It boils down to:
43
+
44
+ @$ nohup script/runner -e RAILS_ENV /path/to/DoSomething.rb@
45
+
46
+ And then looking up the PID by matching on /path/to/DoSomething.rb via grep and use kill to send the term signal.
@@ -0,0 +1,71 @@
1
+ # Copyright (c) 2008 Zetetic LLC
2
+
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ # OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ module Looper
25
+
26
+ def trap_signals
27
+ sigtrap = proc {
28
+ puts "caught trapped signal, shutting down"
29
+ @run = false
30
+ }
31
+ ["SIGTERM", "SIGINT", "SIGHUP"].each do |signal|
32
+ trap signal, sigtrap
33
+ end
34
+ end
35
+
36
+ def loopme(run_every = 10)
37
+ # we don't want to delay output to sdtout until the program stops, we want feedback!
38
+ $stdout.sync=true
39
+
40
+ trap_signals
41
+
42
+ @run = true
43
+
44
+ puts "#{Time.now} process started with #{run_every} loop. kill #{Process.pid} to stop"
45
+
46
+ last_run = Time.now - run_every - 1
47
+ while (@run) do
48
+ now = Time.now
49
+ if last_run + run_every < now
50
+ begin
51
+ yield
52
+ rescue Exception => e
53
+ puts "Uncaught exception bubbled up: \n#{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")} "
54
+ end
55
+ last_run = now
56
+ end
57
+ sleep(2)
58
+ end
59
+ puts "#{Time.now} shutting down"
60
+ end
61
+
62
+ def write_pid(filename, pid)
63
+ file = File.new(filename, "w")
64
+ file.print pid.to_s
65
+ file.close
66
+ end
67
+
68
+ def exit_loop
69
+ @run = false
70
+ end
71
+ end
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "looper"
3
+ s.version = "0.0.3"
4
+ s.date = "2009-01-21"
5
+ s.summary = "Module for really simple daemons"
6
+ s.email = "wgray@zetetic.net"
7
+ s.homepage = "http://github.com/billymeltdown/looper"
8
+ s.description = "Looper is a module that your class can use to become a really, really simple daemon"
9
+ s.has_rdoc = false
10
+ s.authors = ["Billy Gray", "Stephen Lombardo"]
11
+ s.files = [ "README.textile",
12
+ "looper.gemspec",
13
+ "lib/looper.rb" ]
14
+ s.require_paths = ["lib"]
15
+ s.test_files = [ ]
16
+ s.rdoc_options = [ ]
17
+ s.extra_rdoc_files = [ ]
18
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: looper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Billy Gray
8
+ - Stephen Lombardo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-01-21 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Looper is a module that your class can use to become a really, really simple daemon
18
+ email: wgray@zetetic.net
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - README.textile
27
+ - looper.gemspec
28
+ - lib/looper.rb
29
+ has_rdoc: false
30
+ homepage: http://github.com/billymeltdown/looper
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ requirements: []
49
+
50
+ rubyforge_project:
51
+ rubygems_version: 1.3.1
52
+ signing_key:
53
+ specification_version: 2
54
+ summary: Module for really simple daemons
55
+ test_files: []
56
+