Permalink
Browse files

Initial import of PackMule from some previous work done for Caring.com

  • Loading branch information...
0 parents commit 8acef153976b0f35f567cbaef30451ad16c35dd9 @chriseppstein committed Mar 31, 2009
Showing with 533 additions and 0 deletions.
  1. +46 −0 README.markdown
  2. +7 −0 TODO.markdown
  3. +28 −0 examples/fibonacci_runner.rb
  4. +30 −0 examples/sleepy_runner.rb
  5. +1 −0 init.rb
  6. +4 −0 lib/pack_mule.rb
  7. +417 −0 lib/pack_mule/runner.rb
@@ -0,0 +1,46 @@
+Pack Mule
+=========
+
+Pack Mule give you the facilities you need to run your code for hours or seconds in parallel across your cluster of Beanstalk workers. You can monitor the progress, coordinate tasks, and get results back when they complete.
+
+Usage Example
+-------------
+We name our runner so that we can query it later. The false argument tells the runner not to
+publish progress updates -- instead we'll be asking for it when we need it.
+
+ >> runner = SleepyRunner.new("this_is_an_arbitrary_name", false)
+ => #<SleepyRunner:0x6444c>
+
+First we can run the tasks in the background and block until they are done:
+
+ >> runner.run
+ => 51
+
+Or we can run it in the background:
+
+ >> task = runner.run_async
+ => [1, 'localhost:11300']
+The enqueue method returns a job reference which is just a tuple of a job id and a beanstalk server.
+
+We can now ask for overall progress:
+
+ >> runner.update_progress
+ => "53.0 / 101.0"
+
+progress is returned as a string that can be eval'd to give a percentage
+or you can split on " / " to get the number of jobs completed and queued.
+
+Any instance with the same name will work:
+
+ >> SleepyRunner.new("this_is_an_arbitrary_name").update_progress
+ => "59.0 / 101.0"
+
+So we wait a while and ask for an updated progress
+
+ >> runner.update_progress
+ => "101.0 / 101.0"
+
+Now that it's finished, we can access our return value now:
+
+ >> runner.get_return_value!
+ => 53
@@ -0,0 +1,7 @@
+Things left to do for an initial release
+========================================
+
+1. Use [Moneta](http://github.com/wycats/moneta/tree/master) as an abstraction layer on top of Memcached. Any Key/Value store that all processes can access can be used -- locking is handled by elock.
+2. Build an initialzier
+3. Build an installer
+4. Tests, tests, tests.
@@ -0,0 +1,28 @@
+# Jobs::FibonacciRunner.new("fib1").fibonacci(10)
+class FibonacciRunner < PackMule::Runner
+ def initialize(*args)
+ super
+ @record_return_values = true
+ end
+
+ # Be careful, this is a really good way to swamp your workers.
+ def fibonacci(n)
+ if n <= 0
+ 0
+ elsif n == 1
+ 1
+ elsif n == 2
+ 3
+ else
+ # TODO: This could be optimized by recording which job is going to calculate fibonacci(n) and
+ # deferring to that one instead of a new one.
+ j1 = enqueue :fibonacci, n - 1
+ j2 = enqueue :fibonacci, n - 2
+ deferred_result :add_together, [j1, j2]
+ end
+ end
+
+ def add_together(values)
+ values.first + values.last
+ end
+end
@@ -0,0 +1,30 @@
+require 'pack_mule'
+
+# This runner enqueue some jobs to sleep for a short time and returns the total time spent asleep.
+class SleepyRunner < PackMule::Runner
+
+ def initialize(*args)
+ super
+ @record_return_values = true
+ end
+
+ def run_async(nap_count = 100)
+ enqueue :run
+ end
+
+ def run(nap_count = 100)
+ jobs = []
+ nap_count.times do
+ jobs << enqueue :snooze, rand(2)
+ end
+ deferred_result :wakeup, jobs
+ end
+
+ def wakeup(durations)
+ durations.inject(0){|total, duration| total + duration}
+ end
+
+ def snooze(duration)
+ sleep duration
+ end
+end
@@ -0,0 +1 @@
+require File.join(File.dirname(__FILE__), 'lib', 'pack_mule')
@@ -0,0 +1,4 @@
+module PackMule
+end
+
+require File.join(File.dirname(__FILE__), 'pack_mule', 'runner')
Oops, something went wrong.

0 comments on commit 8acef15

Please sign in to comment.