say_when 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +1 -0
  4. data/generators/say_when_migration/say_when_migration_generator.rb +11 -0
  5. data/generators/say_when_migration/templates/migration.rb +48 -0
  6. data/lib/generators/.DS_Store +0 -0
  7. data/lib/generators/say_when/migration/migration_generator.rb +13 -0
  8. data/lib/generators/say_when/migration/templates/migration.rb +47 -0
  9. data/lib/say_when/base_job.rb +96 -0
  10. data/lib/say_when/cron_expression.rb +621 -0
  11. data/lib/say_when/processor/active_messaging.rb +22 -0
  12. data/lib/say_when/processor/base.rb +17 -0
  13. data/lib/say_when/processor/simple.rb +15 -0
  14. data/lib/say_when/scheduler.rb +129 -0
  15. data/lib/say_when/storage/active_record/acts.rb +85 -0
  16. data/lib/say_when/storage/active_record/job.rb +85 -0
  17. data/lib/say_when/storage/active_record/job_execution.rb +17 -0
  18. data/lib/say_when/storage/memory/base.rb +34 -0
  19. data/lib/say_when/storage/memory/job.rb +48 -0
  20. data/lib/say_when/storage/mongoid/job.rb +15 -0
  21. data/lib/say_when/tasks.rb +22 -0
  22. data/lib/say_when/triggers/base.rb +11 -0
  23. data/lib/say_when/triggers/cron_strategy.rb +22 -0
  24. data/lib/say_when/triggers/once_strategy.rb +30 -0
  25. data/lib/say_when/version.rb +3 -0
  26. data/lib/say_when.rb +28 -0
  27. data/lib/tasks/say_when.rake +2 -0
  28. data/say_when.gemspec +26 -0
  29. data/spec/active_record_spec_helper.rb +11 -0
  30. data/spec/db/schema.rb +36 -0
  31. data/spec/db/test.db +0 -0
  32. data/spec/mongoid_spec_helper.rb +7 -0
  33. data/spec/say_when/cron_expression_spec.rb +72 -0
  34. data/spec/say_when/scheduler_spec.rb +76 -0
  35. data/spec/say_when/storage/active_record/job_spec.rb +84 -0
  36. data/spec/say_when/storage/memory/job_spec.rb +31 -0
  37. data/spec/say_when/storage/memory/trigger_spec.rb +54 -0
  38. data/spec/say_when/storage/mongoid/trigger_spec.rb +57 -0
  39. data/spec/spec.opts +4 -0
  40. data/spec/spec_helper.rb +46 -0
  41. data/spec/support/models.rb +31 -0
  42. metadata +224 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in say_when.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,11 @@
1
+ class SayWhenMigrationGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'migration.rb', 'db/migrate'
5
+ end
6
+ end
7
+
8
+ def file_name
9
+ "say_when_migration"
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ class SayWhenMigration < ActiveRecord::Migration
2
+ def self.up
3
+
4
+ create_table :say_when_jobs, :force => true do |t|
5
+
6
+ t.string :group
7
+ t.string :name
8
+
9
+ t.string :status
10
+
11
+ t.string :trigger_strategy
12
+ t.text :trigger_options
13
+
14
+ t.timestamp :last_fire_at
15
+ t.timestamp :next_fire_at
16
+
17
+ t.timestamp :start_at
18
+ t.timestamp :end_at
19
+
20
+ t.string :job_class
21
+ t.string :job_method
22
+ t.text :data
23
+
24
+ t.string :scheduled_type
25
+ t.integer :scheduled_id
26
+
27
+ t.timestamps
28
+ end
29
+
30
+ create_table :say_when_job_executions, :force => true do |t|
31
+ t.integer :job_id
32
+ t.string :status
33
+ t.text :result
34
+ t.datetime :start_at
35
+ t.datetime :end_at
36
+ end
37
+
38
+ add_index :say_when_jobs, :status
39
+ add_index :say_when_jobs, :next_fire_at
40
+ add_index :say_when_job_executions, :job_id
41
+ end
42
+
43
+
44
+ def self.down
45
+ drop_table :say_when_job_executions
46
+ drop_table :say_when_jobs
47
+ end
48
+ end
Binary file
@@ -0,0 +1,13 @@
1
+ module SayWhen
2
+ class MigrationGenerator < Rails::Generator::Base
3
+ def manifest
4
+ record do |m|
5
+ m.migration_template 'migration.rb', 'db/migrate'
6
+ end
7
+ end
8
+
9
+ def file_name
10
+ "say_when_migration"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,47 @@
1
+ class SayWhenMigration < ActiveRecord::Migration
2
+ def self.up
3
+
4
+ create_table :say_when_jobs, :force => true do |t|
5
+
6
+ t.string :group
7
+ t.string :name
8
+
9
+ t.string :status
10
+
11
+ t.string :trigger_strategy
12
+ t.text :trigger_options
13
+
14
+ t.timestamp :last_fire_at
15
+ t.timestamp :next_fire_at
16
+
17
+ t.timestamp :start_at
18
+ t.timestamp :end_at
19
+
20
+ t.string :job_class
21
+ t.string :job_method
22
+ t.text :data
23
+
24
+ t.string :scheduled_type
25
+ t.integer :scheduled_id
26
+
27
+ t.timestamps
28
+ end
29
+
30
+ create_table :say_when_job_executions, :force => true do |t|
31
+ t.integer :job_id
32
+ t.string :status
33
+ t.text :result
34
+ t.datetime :start_at
35
+ t.datetime :end_at
36
+ end
37
+
38
+ add_index :say_when_jobs, :status
39
+ add_index :say_when_jobs, :next_fire_at
40
+ end
41
+
42
+ def self.down
43
+ drop_table :say_when_job_executions
44
+ drop_table :say_when_jobs
45
+ end
46
+
47
+ end
@@ -0,0 +1,96 @@
1
+ module SayWhen
2
+ module BaseJob
3
+
4
+ # ready to be run, just waiting for its turn
5
+ STATE_WAITING = 'waiting'
6
+
7
+ # has been acquired b/c it is time to be triggered
8
+ STATE_ACQUIRED = 'acquired'
9
+
10
+ # # related job for the trigger is executing
11
+ # STATE_EXECUTING = 'executing'
12
+
13
+ # "Complete" means the trigger has no remaining fire times
14
+ STATE_COMPLETE = 'complete'
15
+
16
+ # A Trigger arrives at the error state when the scheduler
17
+ # attempts to fire it, but cannot due to an error creating and executing
18
+ # its related job.
19
+ STATE_ERROR = 'error'
20
+
21
+ def lock
22
+ @_lock ||= Mutex.new
23
+ end
24
+
25
+ def trigger
26
+ @trigger ||= load_trigger
27
+ end
28
+
29
+ def fired
30
+ self.lock.synchronize {
31
+ fired = Time.now
32
+ next_fire = trigger.next_fire_at(fired) rescue nil
33
+ self.last_fire_at = fired
34
+ self.next_fire_at = next_fire
35
+
36
+ if next_fire.nil?
37
+ self.status = STATE_COMPLETE
38
+ else
39
+ self.status = STATE_WAITING
40
+ end
41
+ }
42
+ end
43
+
44
+ def release
45
+ self.lock.synchronize {
46
+ if self.status == STATE_ACQUIRED
47
+ self.status = STATE_WAITING
48
+ end
49
+ }
50
+ end
51
+
52
+ def execute
53
+ self.execute_job(data)
54
+ end
55
+
56
+ def load_trigger
57
+ strategy = trigger_strategy || :once
58
+ require "say_when/triggers/#{strategy}_strategy"
59
+ trigger_class_name = "SayWhen::Triggers::#{strategy.to_s.camelize}Strategy"
60
+ trigger_class = trigger_class_name.constantize
61
+ trigger_class.new(trigger_options)
62
+ end
63
+
64
+ def execute_job(options)
65
+ task_method = (self.job_method || 'execute').to_s
66
+ task = get_task(task_method)
67
+ task.send(task_method, options)
68
+ end
69
+
70
+ def get_task(task_method)
71
+ task = nil
72
+
73
+ if self.job_class
74
+ tc = self.job_class.constantize
75
+ if tc.respond_to?(task_method)
76
+ task = tc
77
+ else
78
+ to = tc.new
79
+ if to.respond_to?(task_method)
80
+ task = to
81
+ else
82
+ raise "Neither '#{self.job_class}' class nor instance respond to '#{task_method}'"
83
+ end
84
+ end
85
+ elsif self.scheduled
86
+ if self.scheduled.respond_to?(task_method)
87
+ task = self.scheduled
88
+ else
89
+ raise "Scheduled '#{self.scheduled.inspect}' does not respond to '#{task_method}'"
90
+ end
91
+ end
92
+ task
93
+ end
94
+
95
+ end
96
+ end