rpush 2.0.0.beta1 → 2.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rpush/daemon.rb +3 -3
- data/lib/rpush/daemon/adm/delivery.rb +6 -6
- data/lib/rpush/daemon/app_runner.rb +52 -66
- data/lib/rpush/daemon/dispatcher_loop.rb +27 -22
- data/lib/rpush/daemon/feeder.rb +1 -1
- data/lib/rpush/daemon/proc_title.rb +2 -2
- data/lib/rpush/daemon/retryable_error.rb +2 -0
- data/lib/rpush/daemon/signal_handler.rb +1 -1
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +6 -2
- data/lib/rpush/daemon/string_helpers.rb +15 -0
- data/lib/rpush/daemon/synchronizer.rb +44 -0
- data/lib/rpush/embed.rb +1 -1
- data/lib/rpush/push.rb +1 -1
- data/lib/rpush/version.rb +1 -1
- data/spec/functional/synchronization_spec.rb +46 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/client/active_record/apns/notification_spec.rb +2 -2
- data/spec/unit/daemon/adm/delivery_spec.rb +2 -2
- data/spec/unit/daemon/app_runner_spec.rb +32 -98
- data/spec/unit/daemon/dispatcher_loop_spec.rb +0 -13
- data/spec/unit/daemon/feeder_spec.rb +2 -2
- data/spec/unit/daemon/signal_handler_spec.rb +3 -3
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +1 -0
- data/spec/unit/daemon_spec.rb +3 -2
- data/spec/unit/embed_spec.rb +2 -2
- data/spec/unit/logger_spec.rb +7 -5
- data/spec/unit/push_spec.rb +4 -3
- metadata +6 -8
- data/lib/rpush/daemon/dispatcher_loop_collection.rb +0 -33
- data/lib/rpush/daemon/too_many_requests_error.rb +0 -20
- data/spec/unit/daemon/dispatcher_loop_collection_spec.rb +0 -37
- data/spec/unit/daemon/too_many_requests_error_spec.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 09d2df386688b4c0ac01e8aab5e4c725257a3263
|
4
|
+
data.tar.gz: a7233c67417785808daf0e8d0f637d17b31a33b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e19a18011c6e4e06b84deb49b82172ebb580a71ba8aef64e7ba6dce9edfc8aa42273bc131643a1f174aa9a30429b9797617e0661f7005eb657f9d9f1daf0b76
|
7
|
+
data.tar.gz: 47c703cdd66bb3fd80327d991604d0ee573db02b4324023484a90ac5ce7793cd022906ea3b1f424c97390edf7e59e13649c41efc9f2de9cadf68859fbc937f01
|
data/lib/rpush/daemon.rb
CHANGED
@@ -8,18 +8,18 @@ require 'rpush/daemon/errors'
|
|
8
8
|
require 'rpush/daemon/constants'
|
9
9
|
require 'rpush/daemon/reflectable'
|
10
10
|
require 'rpush/daemon/loggable'
|
11
|
+
require 'rpush/daemon/string_helpers'
|
11
12
|
require 'rpush/daemon/interruptible_sleep'
|
12
13
|
require 'rpush/daemon/delivery_error'
|
13
14
|
require 'rpush/daemon/retryable_error'
|
14
|
-
require 'rpush/daemon/too_many_requests_error'
|
15
15
|
require 'rpush/daemon/delivery'
|
16
16
|
require 'rpush/daemon/feeder'
|
17
17
|
require 'rpush/daemon/batch'
|
18
18
|
require 'rpush/daemon/queue_payload'
|
19
|
+
require 'rpush/daemon/synchronizer'
|
19
20
|
require 'rpush/daemon/app_runner'
|
20
21
|
require 'rpush/daemon/tcp_connection'
|
21
22
|
require 'rpush/daemon/dispatcher_loop'
|
22
|
-
require 'rpush/daemon/dispatcher_loop_collection'
|
23
23
|
require 'rpush/daemon/dispatcher/http'
|
24
24
|
require 'rpush/daemon/dispatcher/tcp'
|
25
25
|
require 'rpush/daemon/dispatcher/apns_tcp'
|
@@ -55,7 +55,7 @@ module Rpush
|
|
55
55
|
Process.daemon if daemonize?
|
56
56
|
initialize_store
|
57
57
|
write_pid_file
|
58
|
-
|
58
|
+
Synchronizer.sync
|
59
59
|
|
60
60
|
# No further store connections will be made from this thread.
|
61
61
|
store.release_connection
|
@@ -36,10 +36,10 @@ module Rpush
|
|
36
36
|
end
|
37
37
|
mark_delivered
|
38
38
|
end
|
39
|
+
rescue Rpush::RateLimitError => error
|
40
|
+
handle_rate_limited(error)
|
39
41
|
rescue Rpush::RetryableError => error
|
40
42
|
handle_retryable(error)
|
41
|
-
rescue Rpush::TooManyRequestsError => error
|
42
|
-
handle_too_many_requests(error)
|
43
43
|
rescue StandardError => error
|
44
44
|
mark_failed(error)
|
45
45
|
raise
|
@@ -58,7 +58,7 @@ module Rpush
|
|
58
58
|
when 401
|
59
59
|
unauthorized(response)
|
60
60
|
when 429
|
61
|
-
|
61
|
+
rate_limited(response)
|
62
62
|
when 500
|
63
63
|
internal_server_error(current_registration_id)
|
64
64
|
when 503
|
@@ -94,7 +94,7 @@ module Rpush
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
def
|
97
|
+
def handle_rate_limited(error)
|
98
98
|
if @sent_registration_ids.empty?
|
99
99
|
# none sent yet, just resend after the specified retry-after response.header
|
100
100
|
retry_delivery(@notification, error.response)
|
@@ -129,9 +129,9 @@ module Rpush
|
|
129
129
|
fail Rpush::RetryableError.new(response.code.to_i, @notification.id, 'ADM responded with an Unauthorized Error.', response)
|
130
130
|
end
|
131
131
|
|
132
|
-
def
|
132
|
+
def rate_limited(response)
|
133
133
|
# raise error so the current notification stops sending messages to remaining reg ids
|
134
|
-
fail Rpush::
|
134
|
+
fail Rpush::RateLimitError.new(response.code.to_i, @notification.id, 'Exceeded maximum allowable rate of messages.', response)
|
135
135
|
end
|
136
136
|
|
137
137
|
def internal_server_error(current_registration_id)
|
@@ -4,64 +4,73 @@ module Rpush
|
|
4
4
|
extend Reflectable
|
5
5
|
include Reflectable
|
6
6
|
include Loggable
|
7
|
-
|
8
|
-
class << self
|
9
|
-
attr_reader :runners
|
10
|
-
end
|
7
|
+
include StringHelpers
|
11
8
|
|
12
9
|
@runners = {}
|
13
10
|
|
14
11
|
def self.enqueue(notifications)
|
15
12
|
notifications.group_by(&:app_id).each do |app_id, group|
|
16
|
-
|
17
|
-
runners[app_id].enqueue(group) if runners[app_id]
|
13
|
+
start_app_with_id(app_id) unless @runners[app_id]
|
14
|
+
@runners[app_id].enqueue(group) if @runners[app_id]
|
18
15
|
end
|
16
|
+
|
19
17
|
ProcTitle.update
|
20
18
|
end
|
21
19
|
|
22
|
-
def self.
|
23
|
-
|
24
|
-
apps.each { |app| sync_app(app) }
|
25
|
-
removed = runners.keys - apps.map(&:id)
|
26
|
-
removed.each { |app_id| runners.delete(app_id).stop }
|
27
|
-
ProcTitle.update
|
20
|
+
def self.start_app_with_id(app_id)
|
21
|
+
start_app(Rpush::Daemon.store.app(app_id))
|
28
22
|
end
|
29
23
|
|
30
|
-
def self.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
rescue StandardError => e
|
39
|
-
Rpush.logger.error("[#{app.name}] Exception raised during startup. Notifications will not be delivered for this app.")
|
40
|
-
Rpush.logger.error(e)
|
41
|
-
reflect(:error, e)
|
42
|
-
end
|
43
|
-
end
|
24
|
+
def self.start_app(app)
|
25
|
+
@runners[app.id] = new(app)
|
26
|
+
@runners[app.id].start
|
27
|
+
rescue StandardError => e
|
28
|
+
@runners.delete(app.id)
|
29
|
+
Rpush.logger.error("[#{app.name}] Exception raised during startup. Notifications will not be delivered for this app.")
|
30
|
+
Rpush.logger.error(e)
|
31
|
+
reflect(:error, e)
|
44
32
|
end
|
45
33
|
|
46
|
-
def self.
|
47
|
-
|
34
|
+
def self.stop_app(app_id)
|
35
|
+
@runners.delete(app_id).stop
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.app_running?(app)
|
39
|
+
@runners.key?(app.id)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.app_ids
|
43
|
+
@runners.keys
|
48
44
|
end
|
49
45
|
|
50
46
|
def self.stop
|
51
|
-
runners.values.map(&:stop)
|
52
|
-
runners.clear
|
47
|
+
@runners.values.map(&:stop)
|
48
|
+
@runners.clear
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.total_dispatchers
|
52
|
+
@runners.values.sum(&:num_dispatcher_loops)
|
53
53
|
end
|
54
54
|
|
55
|
-
def self.
|
56
|
-
runners.values.sum(&:
|
55
|
+
def self.total_queued
|
56
|
+
@runners.values.sum(&:queue_size)
|
57
57
|
end
|
58
58
|
|
59
|
-
def self.
|
60
|
-
runners.
|
59
|
+
def self.num_dispatchers_for_app(app)
|
60
|
+
runner = @runners[app.id]
|
61
|
+
runner ? runner.num_dispatcher_loops : 0
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.decrement_dispatchers(app, num)
|
65
|
+
@runners[app.id].decrement_dispatchers(num)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.increment_dispatchers(app, num)
|
69
|
+
@runners[app.id].increment_dispatchers(num)
|
61
70
|
end
|
62
71
|
|
63
72
|
def self.debug
|
64
|
-
runners.values.map(&:debug)
|
73
|
+
@runners.values.map(&:debug)
|
65
74
|
end
|
66
75
|
|
67
76
|
attr_reader :app
|
@@ -69,12 +78,12 @@ module Rpush
|
|
69
78
|
def initialize(app)
|
70
79
|
@app = app
|
71
80
|
@loops = []
|
81
|
+
@dispatcher_loops = []
|
72
82
|
end
|
73
83
|
|
74
84
|
def start
|
75
|
-
app.connections.times { dispatcher_loops.push(new_dispatcher_loop) }
|
85
|
+
app.connections.times { @dispatcher_loops.push(new_dispatcher_loop) }
|
76
86
|
start_loops
|
77
|
-
log_info("Started, #{dispatchers_str}.")
|
78
87
|
end
|
79
88
|
|
80
89
|
def stop
|
@@ -103,31 +112,18 @@ module Rpush
|
|
103
112
|
end
|
104
113
|
end
|
105
114
|
|
106
|
-
def sync(app)
|
107
|
-
@app = app
|
108
|
-
diff = dispatcher_loops.size - app.connections
|
109
|
-
return if diff == 0
|
110
|
-
if diff > 0
|
111
|
-
decrement_dispatchers(diff)
|
112
|
-
log_info("Stopped #{dispatchers_str(diff)}. #{dispatchers_str} running.")
|
113
|
-
else
|
114
|
-
increment_dispatchers(diff.abs)
|
115
|
-
log_info("Started #{dispatchers_str(diff)}. #{dispatchers_str} running.")
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
115
|
def decrement_dispatchers(num)
|
120
|
-
num.times { dispatcher_loops.pop }
|
116
|
+
num.times { @dispatcher_loops.pop.stop }
|
121
117
|
end
|
122
118
|
|
123
119
|
def increment_dispatchers(num)
|
124
|
-
num.times { dispatcher_loops.push(new_dispatcher_loop) }
|
120
|
+
num.times { @dispatcher_loops.push(new_dispatcher_loop) }
|
125
121
|
end
|
126
122
|
|
127
123
|
def debug
|
128
124
|
dispatcher_details = {}
|
129
125
|
|
130
|
-
dispatcher_loops.
|
126
|
+
@dispatcher_loops.each_with_index do |dispatcher_loop, i|
|
131
127
|
dispatcher_details[i] = {
|
132
128
|
started_at: dispatcher_loop.started_at.iso8601,
|
133
129
|
dispatched: dispatcher_loop.dispatch_count,
|
@@ -144,7 +140,7 @@ module Rpush
|
|
144
140
|
end
|
145
141
|
|
146
142
|
def num_dispatcher_loops
|
147
|
-
dispatcher_loops.size
|
143
|
+
@dispatcher_loops.size
|
148
144
|
end
|
149
145
|
|
150
146
|
private
|
@@ -160,8 +156,8 @@ module Rpush
|
|
160
156
|
end
|
161
157
|
|
162
158
|
def stop_dispatcher_loops
|
163
|
-
dispatcher_loops.stop
|
164
|
-
@dispatcher_loops
|
159
|
+
@dispatcher_loops.map(&:stop)
|
160
|
+
@dispatcher_loops.clear
|
165
161
|
end
|
166
162
|
|
167
163
|
def new_dispatcher_loop
|
@@ -179,16 +175,6 @@ module Rpush
|
|
179
175
|
def queue
|
180
176
|
@queue ||= Queue.new
|
181
177
|
end
|
182
|
-
|
183
|
-
def dispatcher_loops
|
184
|
-
@dispatcher_loops ||= Rpush::Daemon::DispatcherLoopCollection.new
|
185
|
-
end
|
186
|
-
|
187
|
-
def dispatchers_str(count = num_dispatcher_loops)
|
188
|
-
count = count.abs
|
189
|
-
str = count == 1 ? 'dispatcher' : 'dispatchers'
|
190
|
-
"#{count} #{str}"
|
191
|
-
end
|
192
178
|
end
|
193
179
|
end
|
194
180
|
end
|
@@ -6,7 +6,7 @@ module Rpush
|
|
6
6
|
|
7
7
|
attr_reader :started_at, :dispatch_count
|
8
8
|
|
9
|
-
|
9
|
+
STOP = :stop
|
10
10
|
|
11
11
|
def initialize(queue, dispatcher)
|
12
12
|
@queue = queue
|
@@ -23,8 +23,17 @@ module Rpush
|
|
23
23
|
|
24
24
|
@thread = Thread.new do
|
25
25
|
loop do
|
26
|
-
|
27
|
-
|
26
|
+
payload = @queue.pop
|
27
|
+
if stop_payload?(payload)
|
28
|
+
break if should_stop?(payload)
|
29
|
+
|
30
|
+
# Intended for another dispatcher loop.
|
31
|
+
@queue.push(payload)
|
32
|
+
Thread.pass
|
33
|
+
sleep 0.1
|
34
|
+
else
|
35
|
+
dispatch(payload)
|
36
|
+
end
|
28
37
|
end
|
29
38
|
|
30
39
|
Rpush::Daemon.store.release_connection
|
@@ -32,31 +41,27 @@ module Rpush
|
|
32
41
|
end
|
33
42
|
|
34
43
|
def stop
|
35
|
-
@
|
36
|
-
end
|
37
|
-
|
38
|
-
def wakeup
|
39
|
-
@queue.push(WAKEUP) if @thread
|
40
|
-
end
|
41
|
-
|
42
|
-
def wait
|
44
|
+
@queue.push([STOP, object_id]) if @thread
|
43
45
|
@thread.join if @thread
|
44
46
|
@dispatcher.cleanup
|
45
47
|
end
|
46
48
|
|
47
|
-
|
49
|
+
private
|
48
50
|
|
49
|
-
def
|
50
|
-
payload
|
51
|
-
|
51
|
+
def stop_payload?(payload)
|
52
|
+
payload.is_a?(Array) && payload.first == STOP
|
53
|
+
end
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
def should_stop?(payload)
|
56
|
+
payload.last == object_id
|
57
|
+
end
|
58
|
+
|
59
|
+
def dispatch(payload)
|
60
|
+
@dispatch_count += 1
|
61
|
+
@dispatcher.dispatch(payload)
|
62
|
+
rescue StandardError => e
|
63
|
+
log_error(e)
|
64
|
+
reflect(:error, e)
|
60
65
|
end
|
61
66
|
end
|
62
67
|
end
|
data/lib/rpush/daemon/feeder.rb
CHANGED
@@ -37,7 +37,7 @@ module Rpush
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def self.enqueue_notifications
|
40
|
-
batch_size = Rpush.config.batch_size - Rpush::Daemon::AppRunner.
|
40
|
+
batch_size = Rpush.config.batch_size - Rpush::Daemon::AppRunner.total_queued
|
41
41
|
return if batch_size <= 0
|
42
42
|
notifications = Rpush::Daemon.store.deliverable_notifications(batch_size)
|
43
43
|
Rpush::Daemon::AppRunner.enqueue(notifications)
|
@@ -6,9 +6,9 @@ module Rpush
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.proc_title
|
9
|
-
total_dispatchers = AppRunner.
|
9
|
+
total_dispatchers = AppRunner.total_dispatchers
|
10
10
|
dispatchers_str = total_dispatchers == 1 ? 'dispatcher' : 'dispatchers'
|
11
|
-
total_queued = AppRunner.
|
11
|
+
total_queued = AppRunner.total_queued
|
12
12
|
format("rpush | %s | %d queued | %d %s", Rpush.config.environment, total_queued, total_dispatchers, dispatchers_str)
|
13
13
|
end
|
14
14
|
end
|
@@ -1,4 +1,7 @@
|
|
1
1
|
class PGError < StandardError; end unless defined?(PGError)
|
2
|
+
module PG
|
3
|
+
class Error < StandardError; end unless defined?(::PG::Error)
|
4
|
+
end
|
2
5
|
class Mysql; class Error < StandardError; end; end unless defined?(Mysql)
|
3
6
|
module Mysql2; class Error < StandardError; end; end unless defined?(Mysql2)
|
4
7
|
module ActiveRecord
|
@@ -17,8 +20,9 @@ module Rpush
|
|
17
20
|
module Store
|
18
21
|
class ActiveRecord
|
19
22
|
module Reconnectable
|
20
|
-
ADAPTER_ERRORS = [::ActiveRecord::StatementInvalid, PGError,
|
21
|
-
Mysql2::Error, ::ActiveRecord::JDBCError,
|
23
|
+
ADAPTER_ERRORS = [::ActiveRecord::StatementInvalid, PGError, PG::Error,
|
24
|
+
Mysql::Error, Mysql2::Error, ::ActiveRecord::JDBCError,
|
25
|
+
SQLite3::Exception]
|
22
26
|
|
23
27
|
def with_database_reconnect_and_retry
|
24
28
|
::ActiveRecord::Base.connection_pool.with_connection do
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Daemon
|
3
|
+
module StringHelpers
|
4
|
+
def pluralize(count, singular, plural = nil)
|
5
|
+
if count == 1 || count =~ /^1(\.0+)?$/
|
6
|
+
word = singular
|
7
|
+
else
|
8
|
+
word = plural || singular.pluralize
|
9
|
+
end
|
10
|
+
|
11
|
+
"#{count || 0} #{word}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Rpush
|
2
|
+
module Daemon
|
3
|
+
class Synchronizer
|
4
|
+
extend Loggable
|
5
|
+
extend StringHelpers
|
6
|
+
|
7
|
+
def self.sync
|
8
|
+
apps = Rpush::Daemon.store.all_apps
|
9
|
+
apps.each { |app| sync_app(app) }
|
10
|
+
removed = AppRunner.app_ids - apps.map(&:id)
|
11
|
+
removed.each { |app_id| AppRunner.stop_app(app_id) }
|
12
|
+
|
13
|
+
ProcTitle.update
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.sync_app(app)
|
17
|
+
unless AppRunner.app_running?(app)
|
18
|
+
AppRunner.start_app(app)
|
19
|
+
log_info("[#{app.name}] Started, #{pluralize(app.connections, 'dispatcher')}.")
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
sync_dispatcher_count(app)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.sync_dispatcher_count(app)
|
27
|
+
num_dispatchers = AppRunner.num_dispatchers_for_app(app)
|
28
|
+
diff = num_dispatchers - app.connections
|
29
|
+
return if diff == 0
|
30
|
+
|
31
|
+
if diff > 0
|
32
|
+
AppRunner.decrement_dispatchers(app, diff)
|
33
|
+
start_stop_str = "Stopped"
|
34
|
+
else
|
35
|
+
AppRunner.increment_dispatchers(app, diff.abs)
|
36
|
+
start_stop_str = "Started"
|
37
|
+
end
|
38
|
+
|
39
|
+
num_dispatchers = AppRunner.num_dispatchers_for_app(app)
|
40
|
+
log_info("[#{app.name}] #{start_stop_str} #{pluralize(diff.abs, 'dispatcher')}. #{num_dispatchers} running.")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/rpush/embed.rb
CHANGED
data/lib/rpush/push.rb
CHANGED
data/lib/rpush/version.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'functional_spec_helper'
|
2
|
+
|
3
|
+
describe 'Synchronization' do
|
4
|
+
let(:timeout) { 10 }
|
5
|
+
let(:app) { Rpush::Gcm::App.new }
|
6
|
+
|
7
|
+
def wait_for_num_dispatchers(num)
|
8
|
+
Timeout.timeout(timeout) do
|
9
|
+
until Rpush::Daemon::AppRunner.num_dispatchers_for_app(app) == num
|
10
|
+
sleep 0.1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
app.name = 'test'
|
17
|
+
app.auth_key = 'abc123'
|
18
|
+
app.connections = 2
|
19
|
+
app.save!
|
20
|
+
|
21
|
+
Rpush.embed
|
22
|
+
wait_for_num_dispatchers(app.connections)
|
23
|
+
end
|
24
|
+
|
25
|
+
after { Timeout.timeout(timeout) { Rpush.shutdown } }
|
26
|
+
|
27
|
+
it 'increments the number of dispatchers' do
|
28
|
+
app.connections += 1
|
29
|
+
app.save!
|
30
|
+
Rpush.sync
|
31
|
+
wait_for_num_dispatchers(app.connections)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'decrements the number of dispatchers' do
|
35
|
+
app.connections -= 1
|
36
|
+
app.save!
|
37
|
+
Rpush.sync
|
38
|
+
wait_for_num_dispatchers(app.connections)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'stops a deleted app' do
|
42
|
+
app.destroy
|
43
|
+
Rpush.sync
|
44
|
+
Rpush::Daemon::AppRunner.app_running?(app).should be_false
|
45
|
+
end
|
46
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
ENV['RAILS_ENV'] = 'test'
|
2
|
+
client = (ENV['CLIENT'] || :active_record).to_sym
|
2
3
|
|
3
|
-
require 'bundler'
|
4
|
+
require 'bundler/setup'
|
4
5
|
Bundler.require(:default)
|
5
|
-
client = (ENV['CLIENT'] || :active_record).to_sym
|
6
6
|
|
7
7
|
unless ENV['TRAVIS'] && ENV['QUALITY'] == 'false'
|
8
8
|
begin
|
@@ -156,7 +156,7 @@ describe Rpush::Client::ActiveRecord::Apns::Notification, 'to_binary' do
|
|
156
156
|
notification.badge = nil
|
157
157
|
notification.sound = nil
|
158
158
|
notification.content_available = true
|
159
|
-
bytes = notification.to_binary.bytes[-4..-1]
|
159
|
+
bytes = notification.to_binary.bytes.to_a[-4..-1]
|
160
160
|
bytes.first.should eq 5 # priority item ID
|
161
161
|
bytes.last.should eq Rpush::Client::ActiveRecord::Apns::Notification::APNS_PRIORITY_CONSERVE_POWER
|
162
162
|
end
|
@@ -166,7 +166,7 @@ describe Rpush::Client::ActiveRecord::Apns::Notification, 'to_binary' do
|
|
166
166
|
notification.badge = nil
|
167
167
|
notification.sound = nil
|
168
168
|
notification.content_available = true
|
169
|
-
bytes = notification.to_binary.bytes[-4..-1]
|
169
|
+
bytes = notification.to_binary.bytes.to_a[-4..-1]
|
170
170
|
bytes.first.should eq 5 # priority item ID
|
171
171
|
bytes.last.should eq Rpush::Client::ActiveRecord::Apns::Notification::APNS_PRIORITY_IMMEDIATE
|
172
172
|
end
|
@@ -134,7 +134,7 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
134
134
|
describe 'a 429 (Too Many Request) response' do
|
135
135
|
let(:http) { double(shutdown: nil) }
|
136
136
|
let(:notification) { Rpush::Adm::Notification.create!(app: app, registration_ids: %w(abc xyz), deliver_after: Time.now, collapse_key: 'sync', data: { 'message' => 'test' }) }
|
137
|
-
let(:
|
137
|
+
let(:rate_limited_response) { double(code: 429, header: { 'retry-after' => 3600 }) }
|
138
138
|
|
139
139
|
it 'should retry the entire notification respecting the Retry-After header if none sent out yet' do
|
140
140
|
response.stub(code: 429, header: { 'retry-after' => 3600 })
|
@@ -167,7 +167,7 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
167
167
|
|
168
168
|
# first request to deliver message that returns too many request response
|
169
169
|
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'xyz'))
|
170
|
-
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(
|
170
|
+
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(rate_limited_response)
|
171
171
|
|
172
172
|
store.should_receive(:update_notification).with do |notif|
|
173
173
|
notif.registration_ids.include?('abc').should be_true
|
@@ -31,104 +31,49 @@ module Rpush
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
describe Rpush::Daemon::AppRunner, 'stop' do
|
35
|
-
let(:runner) { double }
|
36
|
-
before { Rpush::Daemon::AppRunner.runners['app'] = runner }
|
37
|
-
after { Rpush::Daemon::AppRunner.runners.clear }
|
38
|
-
|
39
|
-
it 'stops all runners' do
|
40
|
-
runner.should_receive(:stop)
|
41
|
-
Rpush::Daemon::AppRunner.stop
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
34
|
describe Rpush::Daemon::AppRunner, 'enqueue' do
|
46
|
-
let(:
|
47
|
-
let(:
|
48
|
-
let(:
|
35
|
+
let(:app) { double(id: 1) }
|
36
|
+
let(:notification) { double(app_id: 1) }
|
37
|
+
let(:runner) { double(Rpush::Daemon::AppRunner, enqueue: nil, start: nil, stop: nil) }
|
49
38
|
let(:logger) { double(Rpush::Logger, error: nil, info: nil) }
|
50
39
|
|
51
40
|
before do
|
52
41
|
Rpush.stub(logger: logger)
|
53
42
|
Rpush::Daemon::ProcTitle.stub(:update)
|
54
|
-
Rpush::Daemon::AppRunner.
|
55
|
-
Rpush::Daemon::AppRunner.
|
43
|
+
Rpush::Daemon::AppRunner.stub(new: runner)
|
44
|
+
Rpush::Daemon::AppRunner.start_app(app)
|
56
45
|
end
|
57
46
|
|
58
|
-
after { Rpush::Daemon::AppRunner.
|
47
|
+
after { Rpush::Daemon::AppRunner.stop }
|
59
48
|
|
60
|
-
it 'enqueues notifications on
|
61
|
-
runner.should_receive(:enqueue).with([
|
62
|
-
|
63
|
-
Rpush::Daemon::AppRunner.enqueue([notification1, notification2])
|
49
|
+
it 'enqueues notifications on the runner' do
|
50
|
+
runner.should_receive(:enqueue).with([notification])
|
51
|
+
Rpush::Daemon::AppRunner.enqueue([notification])
|
64
52
|
end
|
65
53
|
|
66
|
-
it '
|
67
|
-
Rpush::Daemon::AppRunner.runners[3].should be_nil
|
54
|
+
it 'starts the app if a runner does not exist' do
|
68
55
|
notification = double(app_id: 3)
|
69
|
-
|
70
|
-
Rpush::Daemon.store = double(app:
|
56
|
+
new_app = double(Rpush::App, id: 3)
|
57
|
+
Rpush::Daemon.store = double(app: new_app)
|
71
58
|
Rpush::Daemon::AppRunner.enqueue([notification])
|
72
|
-
Rpush::Daemon::AppRunner.
|
59
|
+
Rpush::Daemon::AppRunner.app_running?(new_app).should be_true
|
73
60
|
end
|
74
61
|
end
|
75
62
|
|
76
|
-
describe Rpush::Daemon::AppRunner, '
|
77
|
-
let(:app) { double(
|
78
|
-
let(:
|
79
|
-
let(:
|
80
|
-
let(:logger) { double(Rpush::Logger, error: nil, warn: nil) }
|
81
|
-
let(:queue) { Queue.new }
|
82
|
-
let(:store) { double(all_apps: [app]) }
|
63
|
+
describe Rpush::Daemon::AppRunner, 'start_app' do
|
64
|
+
let(:app) { double(id: 1, name: 'test') }
|
65
|
+
let(:runner) { double(Rpush::Daemon::AppRunner, enqueue: nil, start: nil, stop: nil) }
|
66
|
+
let(:logger) { double(Rpush::Logger, error: nil, info: nil) }
|
83
67
|
|
84
68
|
before do
|
85
|
-
app.stub(id: 1)
|
86
|
-
new_app.stub(id: 2)
|
87
|
-
Queue.stub(new: queue)
|
88
|
-
Rpush::Daemon::AppRunner.runners[app.id] = runner
|
89
69
|
Rpush.stub(logger: logger)
|
90
|
-
Rpush::Daemon.stub(store: store)
|
91
|
-
Rpush::Daemon::ProcTitle.stub(:update)
|
92
|
-
end
|
93
|
-
|
94
|
-
after { Rpush::Daemon::AppRunner.runners.clear }
|
95
|
-
|
96
|
-
it 'instructs existing runners to sync' do
|
97
|
-
runner.should_receive(:sync).with(app)
|
98
|
-
Rpush::Daemon::AppRunner.sync
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'starts a runner for a new app' do
|
102
|
-
store.stub(all_apps: [app, new_app])
|
103
|
-
new_runner = double
|
104
|
-
Rpush::Daemon::AppRunner.should_receive(:new).with(new_app).and_return(new_runner)
|
105
|
-
new_runner.should_receive(:start)
|
106
|
-
Rpush::Daemon::AppRunner.sync
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'deletes old runners' do
|
110
|
-
store.stub(all_apps: [])
|
111
|
-
runner.should_receive(:stop)
|
112
|
-
Rpush::Daemon::AppRunner.sync
|
113
70
|
end
|
114
71
|
|
115
72
|
it 'logs an error if the runner could not be started' do
|
116
|
-
|
117
|
-
|
118
|
-
Rpush::Daemon::AppRunner.should_receive(:new).with(new_app).and_return(new_runner)
|
119
|
-
new_runner.stub(:start).and_raise(StandardError)
|
73
|
+
Rpush::Daemon::AppRunner.should_receive(:new).with(app).and_return(runner)
|
74
|
+
runner.stub(:start).and_raise(StandardError)
|
120
75
|
Rpush.logger.should_receive(:error)
|
121
|
-
Rpush::Daemon::AppRunner.
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'reflects errors if the runner could not be started' do
|
125
|
-
store.stub(all_apps: [app, new_app])
|
126
|
-
new_runner = double
|
127
|
-
Rpush::Daemon::AppRunner.should_receive(:new).with(new_app).and_return(new_runner)
|
128
|
-
e = StandardError.new
|
129
|
-
new_runner.stub(:start).and_raise(e)
|
130
|
-
Rpush::Daemon::AppRunner.should_receive(:reflect).with(:error, e)
|
131
|
-
Rpush::Daemon::AppRunner.sync
|
76
|
+
Rpush::Daemon::AppRunner.start_app(app)
|
132
77
|
end
|
133
78
|
end
|
134
79
|
|
@@ -137,15 +82,15 @@ describe Rpush::Daemon::AppRunner, 'debug' do
|
|
137
82
|
environment: 'development', certificate: TEST_CERT, service_name: 'app_runner_spec_service')
|
138
83
|
end
|
139
84
|
let(:logger) { double(Rpush::Logger, info: nil) }
|
140
|
-
let(:store) { double(all_apps: [app]) }
|
85
|
+
let(:store) { double(all_apps: [app], release_connection: nil) }
|
141
86
|
|
142
87
|
before do
|
143
88
|
Rpush::Daemon.stub(config: {}, store: store)
|
144
89
|
Rpush.stub(logger: logger)
|
145
|
-
Rpush::Daemon::AppRunner.
|
90
|
+
Rpush::Daemon::AppRunner.start_app(app)
|
146
91
|
end
|
147
92
|
|
148
|
-
after { Rpush::Daemon::AppRunner.
|
93
|
+
after { Rpush::Daemon::AppRunner.stop_app(app.id) }
|
149
94
|
|
150
95
|
it 'prints debug app states to the log' do
|
151
96
|
Rpush.logger.should_receive(:info).with(kind_of(String))
|
@@ -161,18 +106,16 @@ describe Rpush::Daemon::AppRunner do
|
|
161
106
|
let(:runner) { Rpush::Daemon::AppRunner.new(app) }
|
162
107
|
let(:logger) { double(Rpush::Logger, info: nil) }
|
163
108
|
let(:queue) { Queue.new }
|
164
|
-
let(:
|
165
|
-
let(:
|
166
|
-
start: nil, stop: nil)
|
167
|
-
end
|
109
|
+
let(:service_loop) { double(Rpush::Daemon::AppRunnerSpecService::ServiceLoop, start: nil, stop: nil) }
|
110
|
+
let(:dispatcher_loop) { double(Rpush::Daemon::DispatcherLoop, stop: nil, start: nil) }
|
168
111
|
let(:store) { double(Rpush::Daemon::Store::ActiveRecord, release_connection: nil) }
|
169
112
|
|
170
113
|
before do
|
114
|
+
Rpush::Daemon::DispatcherLoop.stub(new: dispatcher_loop)
|
171
115
|
Rpush::Daemon.stub(store: store)
|
172
116
|
Rpush::Daemon::AppRunnerSpecService::ServiceLoop.stub(new: service_loop)
|
173
117
|
Queue.stub(new: queue)
|
174
118
|
Rpush.stub(logger: logger)
|
175
|
-
Rpush::Daemon::DispatcherLoopCollection.stub(new: dispatcher_loop_collection)
|
176
119
|
end
|
177
120
|
|
178
121
|
describe 'start' do
|
@@ -182,6 +125,11 @@ describe Rpush::Daemon::AppRunner do
|
|
182
125
|
runner.num_dispatcher_loops.should eq 2
|
183
126
|
end
|
184
127
|
|
128
|
+
it 'starts the dispatcher loop' do
|
129
|
+
dispatcher_loop.should_receive(:start)
|
130
|
+
runner.start
|
131
|
+
end
|
132
|
+
|
185
133
|
it 'starts the loops' do
|
186
134
|
service_loop.should_receive(:start)
|
187
135
|
runner.start
|
@@ -209,7 +157,7 @@ describe Rpush::Daemon::AppRunner do
|
|
209
157
|
before { runner.start }
|
210
158
|
|
211
159
|
it 'stops the delivery dispatchers' do
|
212
|
-
|
160
|
+
dispatcher_loop.should_receive(:stop)
|
213
161
|
runner.stop
|
214
162
|
end
|
215
163
|
|
@@ -218,18 +166,4 @@ describe Rpush::Daemon::AppRunner do
|
|
218
166
|
runner.stop
|
219
167
|
end
|
220
168
|
end
|
221
|
-
|
222
|
-
describe 'sync' do
|
223
|
-
before { runner.start }
|
224
|
-
|
225
|
-
it 'reduces the number of dispatchers if needed' do
|
226
|
-
app.stub(connections: 0)
|
227
|
-
expect { runner.sync(app) }.to change(runner, :num_dispatcher_loops).to(0)
|
228
|
-
end
|
229
|
-
|
230
|
-
it 'increases the number of dispatchers if needed' do
|
231
|
-
app.stub(connections: 2)
|
232
|
-
expect { runner.sync(app) }.to change(runner, :num_dispatcher_loops).to(2)
|
233
|
-
end
|
234
|
-
end
|
235
169
|
end
|
@@ -4,8 +4,6 @@ describe Rpush::Daemon::DispatcherLoop do
|
|
4
4
|
def run_dispatcher_loop
|
5
5
|
dispatcher_loop.start
|
6
6
|
dispatcher_loop.stop
|
7
|
-
dispatcher_loop.wakeup
|
8
|
-
dispatcher_loop.wait
|
9
7
|
end
|
10
8
|
|
11
9
|
let(:notification) { double }
|
@@ -37,20 +35,9 @@ describe Rpush::Daemon::DispatcherLoop do
|
|
37
35
|
run_dispatcher_loop
|
38
36
|
end
|
39
37
|
|
40
|
-
it 'instructs the queue to wakeup the thread when told to stop' do
|
41
|
-
queue.should_receive(:push).with(Rpush::Daemon::DispatcherLoop::WAKEUP).and_call_original
|
42
|
-
run_dispatcher_loop
|
43
|
-
end
|
44
|
-
|
45
38
|
describe 'stop' do
|
46
39
|
before do
|
47
40
|
queue.clear
|
48
|
-
queue.push(Rpush::Daemon::DispatcherLoop::WAKEUP)
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'does not attempt to dispatch when a WAKEUP is dequeued' do
|
52
|
-
dispatcher.should_not_receive(:dispatch)
|
53
|
-
run_dispatcher_loop
|
54
41
|
end
|
55
42
|
|
56
43
|
it 'instructs the dispatcher to cleanup' do
|
@@ -33,14 +33,14 @@ describe Rpush::Daemon::Feeder do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'does not load more notifications if the total queue size is equal to the batch size' do
|
36
|
-
Rpush::Daemon::AppRunner.stub(
|
36
|
+
Rpush::Daemon::AppRunner.stub(total_queued: Rpush.config.batch_size)
|
37
37
|
Rpush::Daemon.store.should_not_receive(:deliverable_notifications)
|
38
38
|
start_and_stop
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'limits the batch size if some runners are still processing notifications' do
|
42
42
|
Rpush.config.stub(batch_size: 10)
|
43
|
-
Rpush::Daemon::AppRunner.stub(
|
43
|
+
Rpush::Daemon::AppRunner.stub(total_queued: 6)
|
44
44
|
Rpush::Daemon.store.should_receive(:deliverable_notifications).with(4)
|
45
45
|
start_and_stop
|
46
46
|
end
|
@@ -42,13 +42,13 @@ describe Rpush::Daemon::SignalHandler do
|
|
42
42
|
|
43
43
|
describe 'HUP' do
|
44
44
|
before do
|
45
|
-
Rpush::Daemon::
|
45
|
+
Rpush::Daemon::Synchronizer.stub(:sync)
|
46
46
|
Rpush::Daemon::Feeder.stub(:wakeup)
|
47
47
|
end
|
48
48
|
|
49
|
-
it 'syncs
|
49
|
+
it 'syncs' do
|
50
50
|
with_handler_start_stop do
|
51
|
-
Rpush::Daemon::
|
51
|
+
Rpush::Daemon::Synchronizer.should_receive(:sync)
|
52
52
|
signal_handler('HUP')
|
53
53
|
end
|
54
54
|
end
|
data/spec/unit/daemon_spec.rb
CHANGED
@@ -11,7 +11,8 @@ describe Rpush::Daemon, "when starting" do
|
|
11
11
|
before do
|
12
12
|
Rpush.stub(logger: logger)
|
13
13
|
Rpush::Daemon::Feeder.stub(:start)
|
14
|
-
Rpush::Daemon::
|
14
|
+
Rpush::Daemon::Synchronizer.stub(sync: nil)
|
15
|
+
Rpush::Daemon::AppRunner.stub(stop: nil)
|
15
16
|
Rpush::Daemon.stub(exit: nil, puts: nil)
|
16
17
|
Rpush::Daemon::SignalHandler.stub(start: nil, stop: nil, handle_shutdown_signal: nil)
|
17
18
|
Process.stub(:daemon)
|
@@ -87,7 +88,7 @@ describe Rpush::Daemon, "when starting" do
|
|
87
88
|
end
|
88
89
|
|
89
90
|
it "syncs apps" do
|
90
|
-
Rpush::Daemon::
|
91
|
+
Rpush::Daemon::Synchronizer.should_receive(:sync)
|
91
92
|
Rpush::Daemon.start
|
92
93
|
end
|
93
94
|
|
data/spec/unit/embed_spec.rb
CHANGED
@@ -36,8 +36,8 @@ end
|
|
36
36
|
describe Rpush, 'sync' do
|
37
37
|
before { Rpush.config.embedded = true }
|
38
38
|
|
39
|
-
it 'syncs
|
40
|
-
Rpush::Daemon::
|
39
|
+
it 'syncs' do
|
40
|
+
Rpush::Daemon::Synchronizer.should_receive(:sync)
|
41
41
|
Rpush.sync
|
42
42
|
end
|
43
43
|
end
|
data/spec/unit/logger_spec.rb
CHANGED
@@ -70,11 +70,13 @@ describe Rpush::Logger do
|
|
70
70
|
logger.info("hi mom")
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
unless Rpush.jruby? # These tests do not work on JRuby.
|
74
|
+
it "should not print out the msg if not running in the foreground" do
|
75
|
+
Rpush.config.foreground = false
|
76
|
+
logger = Rpush::Logger.new
|
77
|
+
STDOUT.should_not_receive(:puts).with(/hi mom/)
|
78
|
+
logger.info("hi mom")
|
79
|
+
end
|
78
80
|
end
|
79
81
|
|
80
82
|
it "should prefix log lines with the current time" do
|
data/spec/unit/push_spec.rb
CHANGED
@@ -2,7 +2,8 @@ require 'unit_spec_helper'
|
|
2
2
|
|
3
3
|
describe Rpush, 'push' do
|
4
4
|
before do
|
5
|
-
Rpush::Daemon::
|
5
|
+
Rpush::Daemon::Synchronizer.stub(sync: nil)
|
6
|
+
Rpush::Daemon::AppRunner.stub(wait: nil)
|
6
7
|
Rpush::Daemon::Feeder.stub(start: nil)
|
7
8
|
end
|
8
9
|
|
@@ -16,8 +17,8 @@ describe Rpush, 'push' do
|
|
16
17
|
Rpush.push
|
17
18
|
end
|
18
19
|
|
19
|
-
it 'syncs
|
20
|
-
Rpush::Daemon::
|
20
|
+
it 'syncs' do
|
21
|
+
Rpush::Daemon::Synchronizer.should_receive(:sync)
|
21
22
|
Rpush.push
|
22
23
|
end
|
23
24
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rpush
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian Leitch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
@@ -136,7 +136,6 @@ files:
|
|
136
136
|
- lib/rpush/daemon/dispatcher/http.rb
|
137
137
|
- lib/rpush/daemon/dispatcher/tcp.rb
|
138
138
|
- lib/rpush/daemon/dispatcher_loop.rb
|
139
|
-
- lib/rpush/daemon/dispatcher_loop_collection.rb
|
140
139
|
- lib/rpush/daemon/errors.rb
|
141
140
|
- lib/rpush/daemon/feeder.rb
|
142
141
|
- lib/rpush/daemon/gcm.rb
|
@@ -155,8 +154,9 @@ files:
|
|
155
154
|
- lib/rpush/daemon/store/active_record/reconnectable.rb
|
156
155
|
- lib/rpush/daemon/store/interface.rb
|
157
156
|
- lib/rpush/daemon/store/redis.rb
|
157
|
+
- lib/rpush/daemon/string_helpers.rb
|
158
|
+
- lib/rpush/daemon/synchronizer.rb
|
158
159
|
- lib/rpush/daemon/tcp_connection.rb
|
159
|
-
- lib/rpush/daemon/too_many_requests_error.rb
|
160
160
|
- lib/rpush/daemon/wpns.rb
|
161
161
|
- lib/rpush/daemon/wpns/delivery.rb
|
162
162
|
- lib/rpush/deprecatable.rb
|
@@ -176,6 +176,7 @@ files:
|
|
176
176
|
- spec/functional/gcm_spec.rb
|
177
177
|
- spec/functional/new_app_spec.rb
|
178
178
|
- spec/functional/retry_spec.rb
|
179
|
+
- spec/functional/synchronization_spec.rb
|
179
180
|
- spec/functional/wpns_spec.rb
|
180
181
|
- spec/functional_spec_helper.rb
|
181
182
|
- spec/integration/rpush_spec.rb
|
@@ -212,7 +213,6 @@ files:
|
|
212
213
|
- spec/unit/daemon/delivery_spec.rb
|
213
214
|
- spec/unit/daemon/dispatcher/http_spec.rb
|
214
215
|
- spec/unit/daemon/dispatcher/tcp_spec.rb
|
215
|
-
- spec/unit/daemon/dispatcher_loop_collection_spec.rb
|
216
216
|
- spec/unit/daemon/dispatcher_loop_spec.rb
|
217
217
|
- spec/unit/daemon/feeder_spec.rb
|
218
218
|
- spec/unit/daemon/gcm/delivery_spec.rb
|
@@ -223,7 +223,6 @@ files:
|
|
223
223
|
- spec/unit/daemon/store/active_record/reconnectable_spec.rb
|
224
224
|
- spec/unit/daemon/store/active_record_spec.rb
|
225
225
|
- spec/unit/daemon/tcp_connection_spec.rb
|
226
|
-
- spec/unit/daemon/too_many_requests_error_spec.rb
|
227
226
|
- spec/unit/daemon/wpns/delivery_spec.rb
|
228
227
|
- spec/unit/daemon_spec.rb
|
229
228
|
- spec/unit/deprecatable_spec.rb
|
@@ -267,6 +266,7 @@ test_files:
|
|
267
266
|
- spec/functional/gcm_spec.rb
|
268
267
|
- spec/functional/new_app_spec.rb
|
269
268
|
- spec/functional/retry_spec.rb
|
269
|
+
- spec/functional/synchronization_spec.rb
|
270
270
|
- spec/functional/wpns_spec.rb
|
271
271
|
- spec/functional_spec_helper.rb
|
272
272
|
- spec/integration/rpush_spec.rb
|
@@ -303,7 +303,6 @@ test_files:
|
|
303
303
|
- spec/unit/daemon/delivery_spec.rb
|
304
304
|
- spec/unit/daemon/dispatcher/http_spec.rb
|
305
305
|
- spec/unit/daemon/dispatcher/tcp_spec.rb
|
306
|
-
- spec/unit/daemon/dispatcher_loop_collection_spec.rb
|
307
306
|
- spec/unit/daemon/dispatcher_loop_spec.rb
|
308
307
|
- spec/unit/daemon/feeder_spec.rb
|
309
308
|
- spec/unit/daemon/gcm/delivery_spec.rb
|
@@ -314,7 +313,6 @@ test_files:
|
|
314
313
|
- spec/unit/daemon/store/active_record/reconnectable_spec.rb
|
315
314
|
- spec/unit/daemon/store/active_record_spec.rb
|
316
315
|
- spec/unit/daemon/tcp_connection_spec.rb
|
317
|
-
- spec/unit/daemon/too_many_requests_error_spec.rb
|
318
316
|
- spec/unit/daemon/wpns/delivery_spec.rb
|
319
317
|
- spec/unit/daemon_spec.rb
|
320
318
|
- spec/unit/deprecatable_spec.rb
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module Rpush
|
2
|
-
module Daemon
|
3
|
-
class DispatcherLoopCollection
|
4
|
-
attr_reader :loops
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@loops = []
|
8
|
-
end
|
9
|
-
|
10
|
-
def push(dispatcher_loop)
|
11
|
-
@loops << dispatcher_loop
|
12
|
-
end
|
13
|
-
|
14
|
-
def pop
|
15
|
-
dispatcher_loop = @loops.pop
|
16
|
-
dispatcher_loop.stop
|
17
|
-
dispatcher_loop.wakeup
|
18
|
-
@loops.map(&:wakeup)
|
19
|
-
dispatcher_loop.wait
|
20
|
-
end
|
21
|
-
|
22
|
-
def size
|
23
|
-
@loops.size
|
24
|
-
end
|
25
|
-
|
26
|
-
def stop
|
27
|
-
@loops.map(&:stop)
|
28
|
-
@loops.map(&:wakeup)
|
29
|
-
@loops.map(&:wait)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Rpush
|
2
|
-
class TooManyRequestsError < StandardError
|
3
|
-
attr_reader :code, :description, :response
|
4
|
-
|
5
|
-
def initialize(code, notification_id, description, response)
|
6
|
-
@code = code
|
7
|
-
@notification_id = notification_id
|
8
|
-
@description = description
|
9
|
-
@response = response
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
message
|
14
|
-
end
|
15
|
-
|
16
|
-
def message
|
17
|
-
"Too many requests for #{@notification_id}, received error #{@code} (#{@description}) - retry after #{@response.header['retry-after']}"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'unit_spec_helper'
|
2
|
-
|
3
|
-
describe Rpush::Daemon::DispatcherLoopCollection do
|
4
|
-
let(:dispatcher_loop) { double.as_null_object }
|
5
|
-
let(:collection) { Rpush::Daemon::DispatcherLoopCollection.new }
|
6
|
-
|
7
|
-
it 'returns the size of the collection' do
|
8
|
-
collection.push(dispatcher_loop)
|
9
|
-
collection.size.should eq 1
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'pops a dispatcher loop from the collection' do
|
13
|
-
collection.push(dispatcher_loop)
|
14
|
-
dispatcher_loop.should_receive(:stop)
|
15
|
-
dispatcher_loop.should_receive(:wakeup)
|
16
|
-
dispatcher_loop.should_receive(:wait)
|
17
|
-
collection.pop
|
18
|
-
collection.size.should eq 0
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'wakes up all dispatcher loops when popping a single dispatcher_loop' do
|
22
|
-
collection.push(dispatcher_loop)
|
23
|
-
dispatcher_loop2 = double.as_null_object
|
24
|
-
collection.push(dispatcher_loop2)
|
25
|
-
dispatcher_loop.should_receive(:wakeup)
|
26
|
-
dispatcher_loop2.should_receive(:wakeup)
|
27
|
-
collection.pop
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'stops all dispatcher detetcloops' do
|
31
|
-
collection.push(dispatcher_loop)
|
32
|
-
dispatcher_loop.should_receive(:stop)
|
33
|
-
dispatcher_loop.should_receive(:wakeup)
|
34
|
-
dispatcher_loop.should_receive(:wait)
|
35
|
-
collection.stop
|
36
|
-
end
|
37
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require "unit_spec_helper"
|
2
|
-
|
3
|
-
describe Rpush::TooManyRequestsError do
|
4
|
-
let(:response) { double(code: 429, header: { 'retry-after' => 3600 }) }
|
5
|
-
let(:error) { Rpush::TooManyRequestsError.new(429, 12, "Too Many Requests", response) }
|
6
|
-
|
7
|
-
it "returns an informative message" do
|
8
|
-
error.to_s.should eq "Too many requests for 12, received error 429 (Too Many Requests) - retry after 3600"
|
9
|
-
end
|
10
|
-
|
11
|
-
it "returns the error code" do
|
12
|
-
error.code.should eq 429
|
13
|
-
end
|
14
|
-
end
|