lita-task-scheduler 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23f66b45e3100b728a6a53a23fa9f166552d7989
4
- data.tar.gz: 4b23ad6c9ed0638905152bb6ac960fa98978a47d
3
+ metadata.gz: c87964e095867fd79b29baed0c909bea11c627b8
4
+ data.tar.gz: c594c7eae944748bcd509e50214814edc629f2fe
5
5
  SHA512:
6
- metadata.gz: 468d8b5438c5d815e570d72d14c727b093f7d584104017c459b1c0a72d2ec6097fba77df538f2e02acfccb7e1615c3b7ab130419845363dbd23ffcc12aff929d
7
- data.tar.gz: 969dc2317064912351a8bdf4af531fd0e1095186d4100298587b298c0cf5c027339672e2311ad08481dad6757b178ec8f4df5d897e5dbd54ee54739f4acb6c6e
6
+ metadata.gz: 407c632bfb744874758e04fa94fdc2af7e69cdea4bbd9d13fdc2ec02c3fb1d25031ced5f2596b1f0e3e5c69b2831d4024247193b2062adb469bbe44147da4658
7
+ data.tar.gz: 8c25068482aadcee6efbbab58aa09085167a71d09758516f43efcb0537be13d218b8565e379e090ec591372fd3a174a7abd49274ee9384450373a4f9b612e186
@@ -1,29 +1,41 @@
1
- require 'pry'
2
- require 'json'
1
+ require 'lita/scheduler'
3
2
 
4
3
  module Lita
5
4
  module Handlers
6
5
  class TaskScheduler < Handler
7
6
 
7
+ # START:routes
8
8
  route(/^schedule\s+"(.+)"\s+in\s+(.+)$/i, :schedule_command, command: true)
9
9
  route(/^show schedule$/i, :show_schedule, command: true)
10
10
  route(/^empty schedule$/i, :empty_schedule, command: true)
11
+ # END:routes
11
12
 
12
- REDIS_TASKS_KEY = name.to_s
13
-
13
+ # START:handlers
14
14
  def show_schedule(payload)
15
- schedule = redis.hgetall(REDIS_TASKS_KEY)
16
-
17
- payload.reply schedule_report(schedule)
15
+ payload.reply schedule_report(scheduler.get_all)
18
16
  end
19
17
 
20
18
  def empty_schedule(payload)
21
- redis.del(REDIS_TASKS_KEY)
19
+ scheduler.clear
20
+ show_schedule payload
21
+ end
22
+
23
+ # START:schedule_command
24
+ def schedule_command(payload)
25
+ task, timing = payload.matches.last
26
+ run_at = parse_timing(timing)
27
+ serialized = command_to_hash(payload.message, new_body: task)
28
+
29
+ defer_task(serialized, run_at)
22
30
  show_schedule payload
23
31
  end
32
+ # END:schedule_command
33
+
34
+ def scheduler
35
+ @_schedule ||= Scheduler.new(redis: redis, logger: Lita.logger)
36
+ end
24
37
 
25
38
  def schedule_report(schedule)
26
- reply = 'Scheduled tasks: '
27
39
  descriptions = []
28
40
 
29
41
  schedule.keys.each do |timestamp|
@@ -36,75 +48,16 @@ module Lita
36
48
  end
37
49
  end
38
50
 
39
- reply + (descriptions.empty? ? 'None.' : descriptions.join)
40
- end
41
-
42
- def schedule_command(payload)
43
- task, timing = payload.matches.last
44
- run_at = parse_timing(timing)
45
- serialized = serialize_message(payload.message, new_body: task)
46
-
47
- defer_task(serialized, run_at)
48
- show_schedule(payload)
51
+ 'Scheduled tasks: ' + (descriptions.empty? ? 'None.' : descriptions.join)
49
52
  end
50
53
 
54
+ # START:defer_task
51
55
  def defer_task(serialized_task, run_at)
52
- key_time = run_at.to_i.to_s
53
-
54
- redis.watch(REDIS_TASKS_KEY)
55
-
56
- tasks = redis.hget(REDIS_TASKS_KEY, key_time) || []
57
-
58
- tasks = JSON.parse(tasks) unless tasks.empty?
59
- tasks << serialized_task
60
-
61
- redis.hset(REDIS_TASKS_KEY, key_time, tasks.to_json)
62
-
63
- redis.unwatch
64
-
65
- tasks
66
- end
67
-
68
- def execute_tasks(serialized_tasks)
69
- serialized_tasks.each do |serialized_task|
70
- Lita.logger.debug "Resending task #{serialized_task}"
71
- resend serialized_task
72
- end
73
- end
74
-
75
- def run_loop
76
- Thread.new do
77
- loop do
78
- tick
79
- sleep 1
80
- end
81
- end
82
- end
83
-
84
- def tick
85
- tasks = find_tasks_due
86
- tasks.each { |t| resend t }
87
- Lita.logger.debug "Task loop done for #{Time.now}"
88
- end
89
-
90
- def find_tasks_due
91
- results = []
92
- timestamps = redis.hkeys(REDIS_TASKS_KEY)
93
-
94
- timestamps.each do |t|
95
- key_time = Time.at(t.to_i)
96
- next unless key_time <= Time.now
97
-
98
- tasks_raw = redis.hget(REDIS_TASKS_KEY, t)
99
- tasks = JSON.parse(tasks_raw)
100
-
101
- results += tasks
102
- redis.hdel(REDIS_TASKS_KEY, t)
103
- end
104
-
105
- results
56
+ scheduler.add(serialized_task, run_at)
106
57
  end
58
+ # END:defer_task
107
59
 
60
+ # START:parse_timing
108
61
  def parse_timing(timing)
109
62
  count, unit = timing.split
110
63
  count = count.to_i
@@ -125,22 +78,14 @@ module Lita
125
78
 
126
79
  Time.now.utc + seconds
127
80
  end
81
+ # END:parse_timing
128
82
 
129
- def rebroadcast(payload)
130
- serialized = serialize_message(payload.message)
131
-
132
- key = "delay_#{rand(100..10_000)}"
133
- redis.set(key, serialized.to_json)
134
- reloaded = JSON.parse redis.get(key), symbolize_names: true
135
-
136
- resend(reloaded)
137
- end
138
-
139
- def resend(serialized)
140
- user = Lita::User.new(serialized.fetch('user_name'))
141
- room = Lita::Room.new(serialized.fetch('room_name'))
83
+ # START:resend_command
84
+ def resend_command(command_hash)
85
+ user = Lita::User.new(command_hash.fetch('user_name'))
86
+ room = Lita::Room.new(command_hash.fetch('room_name'))
142
87
  source = Lita::Source.new(user: user, room: room)
143
- body = "#{robot.name} #{serialized.fetch('body')}"
88
+ body = "#{robot.name} #{command_hash.fetch('body')}"
144
89
 
145
90
  newmsg = Lita::Message.new(
146
91
  robot,
@@ -150,20 +95,42 @@ module Lita
150
95
 
151
96
  robot.receive newmsg
152
97
  end
98
+ # END:resend_command
153
99
 
154
- def serialize_message(message, new_body: nil)
100
+ # START:serialize_message
101
+ def command_to_hash(command, new_body: nil)
155
102
  {
156
- user_name: message.user.name,
157
- room_name: message.source.room,
158
- body: new_body || message.body
103
+ user_name: command.user.name,
104
+ room_name: command.source.room,
105
+ body: new_body || command.body
159
106
  }
160
107
  end
108
+ # END:serialize_message
161
109
 
162
- Lita.register_handler(self)
110
+ def find_tasks_due
111
+ scheduler.find_tasks_due
112
+ end
113
+
114
+ # START:loop_ticks
115
+ def run_loop
116
+ Thread.new do
117
+ loop do
118
+ tick
119
+ sleep 1
120
+ end
121
+ end
122
+ end
163
123
 
164
- on :loaded do
165
- run_loop
124
+ def tick
125
+ tasks = find_tasks_due
126
+ tasks.each { |t| resend_command t }
127
+ Lita.logger.debug "Task loop done for #{Time.now}"
166
128
  end
129
+
130
+ on(:loaded) { run_loop }
131
+ # END:loop_ticks
132
+
133
+ Lita.register_handler(self)
167
134
  end
168
135
  end
169
136
  end
@@ -0,0 +1,62 @@
1
+ require 'json'
2
+
3
+ # START:preamble
4
+ module Lita
5
+ class Scheduler
6
+ REDIS_TASKS_KEY = name.to_s
7
+
8
+ def initialize(redis:, logger:)
9
+ @redis = redis
10
+ @logger = logger
11
+ end
12
+
13
+ attr_reader :redis, :logger
14
+
15
+ def get_all
16
+ redis.hgetall(REDIS_TASKS_KEY)
17
+ end
18
+ # END:preamble
19
+
20
+ # START:store_new
21
+ def add(payload, timestamp)
22
+ key_time = timestamp.to_i.to_s
23
+
24
+ redis.watch(REDIS_TASKS_KEY)
25
+
26
+ tasks = redis.hget(REDIS_TASKS_KEY, key_time) || []
27
+
28
+ tasks = JSON.parse(tasks) unless tasks.empty?
29
+ tasks << payload
30
+
31
+ redis.hset(REDIS_TASKS_KEY, key_time, tasks.to_json)
32
+
33
+ redis.unwatch
34
+ tasks
35
+ end
36
+ # END:store_new
37
+
38
+ def clear
39
+ redis.del(REDIS_TASKS_KEY)
40
+ end
41
+
42
+ # START:find_tasks_due
43
+ def find_tasks_due
44
+ results = []
45
+ timestamps = redis.hkeys(REDIS_TASKS_KEY)
46
+
47
+ timestamps.each do |t|
48
+ key_time = Time.at(t.to_i)
49
+ next unless key_time <= Time.now
50
+
51
+ tasks_raw = redis.hget(REDIS_TASKS_KEY, t)
52
+ tasks = JSON.parse(tasks_raw)
53
+
54
+ results += tasks
55
+ redis.hdel(REDIS_TASKS_KEY, t)
56
+ end
57
+
58
+ results
59
+ end
60
+ # END:find_tasks_due
61
+ end
62
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "lita-task-scheduler"
3
- spec.version = "1.0.0"
3
+ spec.version = "1.1.0"
4
4
  spec.authors = ["Daniel J. Pritchett"]
5
5
  spec.email = ["dpritchett@gmail.com"]
6
6
  spec.description = "Schedule jobs in Lita"
@@ -2,13 +2,17 @@ require 'spec_helper'
2
2
 
3
3
  describe Lita::Handlers::TaskScheduler, lita_handler: true do
4
4
  let(:robot) { Lita::Robot.new(registry) }
5
+ before(:suite) { subject.scheduler.clear }
5
6
 
6
7
  subject { described_class.new(robot) }
7
8
 
9
+ # START:routes
8
10
  describe 'routing' do
9
- it { is_expected.to route('Lita schedule "show schedule" in 2 hours') }
11
+ it { is_expected.to route('Lita schedule "double 4" in 2 hours') }
10
12
  it { is_expected.to route('Lita show schedule') }
13
+ it { is_expected.to route('Lita empty schedule') }
11
14
  end
15
+ # END:routes
12
16
 
13
17
  describe 'functionality' do
14
18
 
@@ -27,6 +31,7 @@ describe Lita::Handlers::TaskScheduler, lita_handler: true do
27
31
  end
28
32
  end
29
33
 
34
+ # START: defer_task
30
35
  describe ':defer_task' do
31
36
  it 'defers any single task' do
32
37
  message = { canary_message: Time.now }
@@ -48,7 +53,9 @@ describe Lita::Handlers::TaskScheduler, lita_handler: true do
48
53
  expect(result).to eq([message] * 6)
49
54
  end
50
55
  end
56
+ # END: defer_task
51
57
 
58
+ # START:find_tasks_due
52
59
  describe ':find_tasks_due' do
53
60
  context 'two tasks are scheduled for five seconds ago' do
54
61
  before { 2.times { subject.defer_task('past_task', Time.now - 5) } }
@@ -69,28 +76,23 @@ describe Lita::Handlers::TaskScheduler, lita_handler: true do
69
76
  end
70
77
  end
71
78
  end
79
+ # END:find_tasks_due
72
80
  end
73
81
 
74
- describe 'execute_tasks' do
75
- it 'resends each task' do
76
- tasks = [{}, {}]
77
-
78
- expect(subject).to receive(:resend).exactly(2).times
79
- subject.execute_tasks(tasks)
80
- end
81
- end
82
-
82
+ # START:loop_ticks
83
83
  describe 'tick' do
84
84
  before { subject.stub(:find_tasks_due).and_return ['a_task'] }
85
85
 
86
86
  it 'should find tasks due and resend them' do
87
87
  expect(subject).to receive(:find_tasks_due)
88
- expect(subject).to receive(:resend).with('a_task')
88
+ expect(subject).to receive(:resend_command).with('a_task')
89
89
 
90
90
  subject.tick
91
91
  end
92
92
  end
93
+ # END:loop_ticks
93
94
 
95
+ # START:parse_timing
94
96
  describe ':parse_timing' do
95
97
  def time_drift(time, expected_seconds:)
96
98
  delta = (Time.now.utc - time).abs
@@ -112,4 +114,5 @@ describe Lita::Handlers::TaskScheduler, lita_handler: true do
112
114
  end
113
115
  end
114
116
  end
117
+ # END:parse_timing
115
118
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita-task-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Pritchett
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-07 00:00:00.000000000 Z
11
+ date: 2018-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lita
@@ -121,6 +121,7 @@ files:
121
121
  - Rakefile
122
122
  - lib/lita-task-scheduler.rb
123
123
  - lib/lita/handlers/task_scheduler.rb
124
+ - lib/lita/scheduler.rb
124
125
  - lita-task-scheduler.gemspec
125
126
  - locales/en.yml
126
127
  - spec/lita/handlers/task_scheduler_spec.rb