rpush 1.0.0 → 2.0.0.beta1

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.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +12 -14
  4. data/bin/rpush +11 -2
  5. data/lib/generators/rpush_generator.rb +2 -0
  6. data/lib/generators/templates/add_adm.rb +5 -5
  7. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +1 -1
  8. data/lib/generators/templates/add_app_to_rapns.rb +2 -2
  9. data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +1 -1
  10. data/lib/generators/templates/add_gcm.rb +32 -32
  11. data/lib/generators/templates/add_rpush.rb +67 -67
  12. data/lib/generators/templates/add_wpns.rb +2 -2
  13. data/lib/generators/templates/create_rapns_apps.rb +5 -5
  14. data/lib/generators/templates/create_rapns_feedback.rb +2 -2
  15. data/lib/generators/templates/create_rapns_notifications.rb +15 -15
  16. data/lib/generators/templates/rpush.rb +10 -7
  17. data/lib/generators/templates/rpush_2_0_0_updates.rb +23 -0
  18. data/lib/rpush.rb +4 -28
  19. data/lib/rpush/client/active_model.rb +21 -0
  20. data/lib/rpush/client/active_model/adm/app.rb +23 -0
  21. data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
  22. data/lib/rpush/client/active_model/adm/notification.rb +28 -0
  23. data/lib/rpush/client/active_model/apns/app.rb +37 -0
  24. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
  25. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
  26. data/lib/rpush/client/active_model/apns/notification.rb +90 -0
  27. data/lib/rpush/client/active_model/gcm/app.rb +19 -0
  28. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
  29. data/lib/rpush/client/active_model/gcm/notification.rb +31 -0
  30. data/lib/rpush/client/active_model/notification.rb +26 -0
  31. data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
  32. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
  33. data/lib/rpush/client/active_model/wpns/app.rb +13 -0
  34. data/lib/rpush/client/active_model/wpns/notification.rb +17 -0
  35. data/lib/rpush/client/active_record.rb +19 -0
  36. data/lib/rpush/client/active_record/adm/app.rb +11 -0
  37. data/lib/rpush/client/active_record/adm/notification.rb +11 -0
  38. data/lib/rpush/client/active_record/apns/app.rb +11 -0
  39. data/lib/rpush/client/active_record/apns/feedback.rb +20 -0
  40. data/lib/rpush/client/active_record/apns/notification.rb +46 -0
  41. data/lib/rpush/client/active_record/app.rb +17 -0
  42. data/lib/rpush/client/active_record/gcm/app.rb +11 -0
  43. data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
  44. data/lib/rpush/client/active_record/notification.rb +38 -0
  45. data/lib/rpush/client/active_record/wpns/app.rb +11 -0
  46. data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
  47. data/lib/rpush/client/redis.rb +35 -0
  48. data/lib/rpush/client/redis/adm/app.rb +14 -0
  49. data/lib/rpush/client/redis/adm/notification.rb +11 -0
  50. data/lib/rpush/client/redis/apns/app.rb +11 -0
  51. data/lib/rpush/client/redis/apns/feedback.rb +20 -0
  52. data/lib/rpush/client/redis/apns/notification.rb +11 -0
  53. data/lib/rpush/client/redis/app.rb +22 -0
  54. data/lib/rpush/client/redis/gcm/app.rb +11 -0
  55. data/lib/rpush/client/redis/gcm/notification.rb +11 -0
  56. data/lib/rpush/client/redis/notification.rb +68 -0
  57. data/lib/rpush/client/redis/wpns/app.rb +11 -0
  58. data/lib/rpush/client/redis/wpns/notification.rb +11 -0
  59. data/lib/rpush/configuration.rb +27 -6
  60. data/lib/rpush/daemon.rb +36 -56
  61. data/lib/rpush/daemon/adm/delivery.rb +50 -52
  62. data/lib/rpush/daemon/apns.rb +6 -5
  63. data/lib/rpush/daemon/apns/delivery.rb +20 -44
  64. data/lib/rpush/daemon/apns/feedback_receiver.rb +11 -8
  65. data/lib/rpush/daemon/app_runner.rb +67 -60
  66. data/lib/rpush/daemon/batch.rb +54 -40
  67. data/lib/rpush/daemon/delivery.rb +13 -3
  68. data/lib/rpush/daemon/delivery_error.rb +10 -2
  69. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +106 -0
  70. data/lib/rpush/daemon/dispatcher/http.rb +3 -3
  71. data/lib/rpush/daemon/dispatcher/tcp.rb +3 -3
  72. data/lib/rpush/daemon/dispatcher_loop.rb +15 -6
  73. data/lib/rpush/daemon/errors.rb +18 -0
  74. data/lib/rpush/daemon/feeder.rb +28 -39
  75. data/lib/rpush/daemon/gcm/delivery.rb +19 -20
  76. data/lib/rpush/daemon/interruptible_sleep.rb +26 -45
  77. data/lib/rpush/daemon/loggable.rb +2 -4
  78. data/lib/rpush/daemon/proc_title.rb +16 -0
  79. data/lib/rpush/daemon/queue_payload.rb +12 -0
  80. data/lib/rpush/daemon/reflectable.rb +3 -5
  81. data/lib/rpush/daemon/retry_header_parser.rb +6 -6
  82. data/lib/rpush/daemon/ring_buffer.rb +16 -0
  83. data/lib/rpush/daemon/service_config_methods.rb +23 -7
  84. data/lib/rpush/daemon/signal_handler.rb +51 -0
  85. data/lib/rpush/daemon/store/active_record.rb +71 -38
  86. data/lib/rpush/daemon/store/active_record/reconnectable.rb +15 -15
  87. data/lib/rpush/daemon/store/interface.rb +19 -0
  88. data/lib/rpush/daemon/store/redis.rb +149 -0
  89. data/lib/rpush/daemon/tcp_connection.rb +6 -11
  90. data/lib/rpush/daemon/wpns/delivery.rb +21 -30
  91. data/lib/rpush/deprecatable.rb +4 -3
  92. data/lib/rpush/deprecation.rb +7 -10
  93. data/lib/rpush/embed.rb +7 -2
  94. data/lib/rpush/logger.rb +11 -15
  95. data/lib/rpush/push.rb +0 -1
  96. data/lib/rpush/reflection.rb +6 -12
  97. data/lib/rpush/version.rb +1 -1
  98. data/lib/tasks/quality.rake +34 -0
  99. data/spec/.rubocop.yml +4 -0
  100. data/spec/functional/adm_spec.rb +3 -6
  101. data/spec/functional/apns_spec.rb +118 -24
  102. data/spec/functional/embed_spec.rb +22 -20
  103. data/spec/functional/gcm_spec.rb +4 -7
  104. data/spec/functional/new_app_spec.rb +61 -0
  105. data/spec/functional/retry_spec.rb +46 -0
  106. data/spec/functional/wpns_spec.rb +3 -6
  107. data/spec/functional_spec_helper.rb +26 -0
  108. data/spec/integration/rpush_spec.rb +13 -0
  109. data/spec/integration/support/gcm_success_response.json +1 -0
  110. data/spec/spec_helper.rb +60 -0
  111. data/spec/support/active_record_setup.rb +48 -0
  112. data/{config → spec/support/config}/database.yml +0 -0
  113. data/spec/support/install.sh +43 -7
  114. data/spec/support/simplecov_helper.rb +9 -5
  115. data/spec/support/simplecov_quality_formatter.rb +10 -6
  116. data/spec/unit/apns_feedback_spec.rb +3 -3
  117. data/spec/unit/{adm → client/active_record/adm}/app_spec.rb +3 -3
  118. data/spec/unit/{adm → client/active_record/adm}/notification_spec.rb +5 -7
  119. data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
  120. data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
  121. data/spec/unit/client/active_record/apns/notification_spec.rb +231 -0
  122. data/spec/unit/client/active_record/app_spec.rb +30 -0
  123. data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
  124. data/spec/unit/{gcm → client/active_record/gcm}/notification_spec.rb +5 -7
  125. data/spec/unit/client/active_record/notification_spec.rb +15 -0
  126. data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
  127. data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
  128. data/spec/unit/configuration_spec.rb +12 -5
  129. data/spec/unit/daemon/adm/delivery_spec.rb +57 -54
  130. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +3 -3
  131. data/spec/unit/daemon/apns/delivery_spec.rb +90 -83
  132. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +24 -17
  133. data/spec/unit/daemon/app_runner_spec.rb +66 -123
  134. data/spec/unit/daemon/batch_spec.rb +52 -115
  135. data/spec/unit/daemon/delivery_spec.rb +15 -1
  136. data/spec/unit/daemon/dispatcher/http_spec.rb +3 -2
  137. data/spec/unit/daemon/dispatcher/tcp_spec.rb +10 -9
  138. data/spec/unit/daemon/dispatcher_loop_spec.rb +7 -12
  139. data/spec/unit/daemon/feeder_spec.rb +40 -39
  140. data/spec/unit/daemon/gcm/delivery_spec.rb +108 -89
  141. data/spec/unit/daemon/reflectable_spec.rb +2 -2
  142. data/spec/unit/daemon/retryable_error_spec.rb +1 -1
  143. data/spec/unit/daemon/service_config_methods_spec.rb +6 -3
  144. data/spec/unit/daemon/signal_handler_spec.rb +72 -0
  145. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +9 -9
  146. data/spec/unit/daemon/store/active_record_spec.rb +38 -47
  147. data/spec/unit/daemon/tcp_connection_spec.rb +22 -34
  148. data/spec/unit/daemon/too_many_requests_error_spec.rb +1 -1
  149. data/spec/unit/daemon/wpns/delivery_spec.rb +61 -50
  150. data/spec/unit/daemon_spec.rb +46 -81
  151. data/spec/unit/embed_spec.rb +4 -2
  152. data/spec/unit/logger_spec.rb +30 -40
  153. data/spec/unit/notification_shared.rb +9 -79
  154. data/spec/unit/push_spec.rb +3 -8
  155. data/spec/unit/reflection_spec.rb +25 -25
  156. data/spec/unit/rpush_spec.rb +1 -2
  157. data/spec/unit_spec_helper.rb +33 -88
  158. metadata +119 -67
  159. data/lib/rpush/TODO +0 -3
  160. data/lib/rpush/adm/app.rb +0 -15
  161. data/lib/rpush/adm/data_validator.rb +0 -11
  162. data/lib/rpush/adm/notification.rb +0 -29
  163. data/lib/rpush/apns/app.rb +0 -29
  164. data/lib/rpush/apns/binary_notification_validator.rb +0 -12
  165. data/lib/rpush/apns/device_token_format_validator.rb +0 -12
  166. data/lib/rpush/apns/feedback.rb +0 -16
  167. data/lib/rpush/apns/notification.rb +0 -84
  168. data/lib/rpush/app.rb +0 -18
  169. data/lib/rpush/daemon/apns/certificate_expired_error.rb +0 -20
  170. data/lib/rpush/daemon/apns/disconnection_error.rb +0 -20
  171. data/lib/rpush/gcm/app.rb +0 -11
  172. data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -11
  173. data/lib/rpush/gcm/notification.rb +0 -30
  174. data/lib/rpush/notification.rb +0 -69
  175. data/lib/rpush/notifier.rb +0 -52
  176. data/lib/rpush/payload_data_size_validator.rb +0 -10
  177. data/lib/rpush/railtie.rb +0 -11
  178. data/lib/rpush/registration_ids_count_validator.rb +0 -10
  179. data/lib/rpush/wpns/app.rb +0 -9
  180. data/lib/rpush/wpns/notification.rb +0 -26
  181. data/lib/tasks/cane.rake +0 -18
  182. data/lib/tasks/rpush.rake +0 -16
  183. data/spec/unit/apns/app_spec.rb +0 -29
  184. data/spec/unit/apns/feedback_spec.rb +0 -9
  185. data/spec/unit/apns/notification_spec.rb +0 -208
  186. data/spec/unit/app_spec.rb +0 -30
  187. data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
  188. data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
  189. data/spec/unit/gcm/app_spec.rb +0 -4
  190. data/spec/unit/notification_spec.rb +0 -15
  191. data/spec/unit/notifier_spec.rb +0 -49
  192. data/spec/unit/wpns/app_spec.rb +0 -4
  193. data/spec/unit/wpns/notification_spec.rb +0 -30
@@ -4,13 +4,14 @@ module Rpush
4
4
  extend ServiceConfigMethods
5
5
 
6
6
  HOSTS = {
7
- :production => ['gateway.push.apple.com', 2195],
8
- :development => ['gateway.sandbox.push.apple.com', 2195], # deprecated
9
- :sandbox => ['gateway.sandbox.push.apple.com', 2195]
7
+ production: ['gateway.push.apple.com', 2195],
8
+ development: ['gateway.sandbox.push.apple.com', 2195], # deprecated
9
+ sandbox: ['gateway.sandbox.push.apple.com', 2195]
10
10
  }
11
11
 
12
- dispatcher :tcp, :host => Proc.new { |app| HOSTS[app.environment.to_sym] }
13
- loops Rpush::Daemon::Apns::FeedbackReceiver
12
+ batch_deliveries true
13
+ dispatcher :apns_tcp, host: proc { |app| HOSTS[app.environment.to_sym] }
14
+ loops Rpush::Daemon::Apns::FeedbackReceiver, if: -> { !Rpush.config.push }
14
15
  end
15
16
  end
16
17
  end
@@ -2,60 +2,36 @@ module Rpush
2
2
  module Daemon
3
3
  module Apns
4
4
  class Delivery < Rpush::Daemon::Delivery
5
- SELECT_TIMEOUT = 0.2
6
- ERROR_TUPLE_BYTES = 6
7
- APN_ERRORS = {
8
- 1 => "Processing error",
9
- 2 => "Missing device token",
10
- 3 => "Missing topic",
11
- 4 => "Missing payload",
12
- 5 => "Missing token size",
13
- 6 => "Missing topic size",
14
- 7 => "Missing payload size",
15
- 8 => "Invalid token",
16
- 255 => "None (unknown error)"
17
- }
18
-
19
- def initialize(app, conneciton, notification, batch)
5
+ def initialize(app, connection, batch)
20
6
  @app = app
21
- @connection = conneciton
22
- @notification = notification
7
+ @connection = connection
23
8
  @batch = batch
24
9
  end
25
10
 
26
11
  def perform
27
- begin
28
- @connection.write(@notification.to_binary)
29
- check_for_error if Rpush.config.check_for_errors
30
- mark_delivered
31
- log_info("#{@notification.id} sent to #{@notification.device_token}")
32
- rescue Rpush::DeliveryError, Rpush::Apns::DisconnectionError => error
33
- mark_failed(error.code, error.description)
34
- raise
35
- end
12
+ @connection.write(batch_to_binary)
13
+ mark_batch_delivered
14
+ describe_deliveries
15
+ rescue StandardError => error
16
+ mark_batch_failed(error)
17
+ raise
18
+ ensure
19
+ @batch.all_processed
36
20
  end
37
21
 
38
22
  protected
39
23
 
40
- def check_for_error
41
- if @connection.select(SELECT_TIMEOUT)
42
- error = nil
43
-
44
- if tuple = @connection.read(ERROR_TUPLE_BYTES)
45
- _, code, notification_id = tuple.unpack("ccN")
46
-
47
- description = APN_ERRORS[code.to_i] || "Unknown error. Possible Rpush bug?"
48
- error = Rpush::DeliveryError.new(code, notification_id, description)
49
- else
50
- error = Rpush::Apns::DisconnectionError.new
51
- end
24
+ def batch_to_binary
25
+ payload = ""
26
+ @batch.each_notification do |notification|
27
+ payload << notification.to_binary
28
+ end
29
+ payload
30
+ end
52
31
 
53
- begin
54
- log_error("Error received, reconnecting...")
55
- @connection.reconnect
56
- ensure
57
- raise error if error
58
- end
32
+ def describe_deliveries
33
+ @batch.each_notification do |notification|
34
+ log_info("#{notification.id} sent to #{notification.device_token}")
59
35
  end
60
36
  end
61
37
  end
@@ -7,28 +7,29 @@ module Rpush
7
7
 
8
8
  TUPLE_BYTES = 38
9
9
  HOSTS = {
10
- :production => ['feedback.push.apple.com', 2196],
11
- :development => ['feedback.sandbox.push.apple.com', 2196], # deprecated
12
- :sandbox => ['feedback.sandbox.push.apple.com', 2196]
10
+ production: ['feedback.push.apple.com', 2196],
11
+ development: ['feedback.sandbox.push.apple.com', 2196], # deprecated
12
+ sandbox: ['feedback.sandbox.push.apple.com', 2196]
13
13
  }
14
14
 
15
15
  def initialize(app)
16
16
  @app = app
17
17
  @host, @port = HOSTS[@app.environment.to_sym]
18
- @poll = Rpush.config.feedback_poll
19
18
  @certificate = app.certificate
20
19
  @password = app.password
21
- @interruptible_sleep = InterruptibleSleep.new
20
+ @interruptible_sleep = InterruptibleSleep.new(Rpush.config.feedback_poll)
22
21
  end
23
22
 
24
23
  def start
25
24
  return if Rpush.config.push
25
+ log_info("APNs Feedback Receiver started.")
26
+ @interruptible_sleep.start
26
27
 
27
28
  @thread = Thread.new do
28
29
  loop do
29
30
  break if @stop
30
31
  check_for_feedback
31
- @interruptible_sleep.sleep @poll
32
+ @interruptible_sleep.sleep
32
33
  end
33
34
 
34
35
  Rpush::Daemon.store.release_connection
@@ -37,7 +38,7 @@ module Rpush
37
38
 
38
39
  def stop
39
40
  @stop = true
40
- @interruptible_sleep.interrupt_sleep
41
+ @interruptible_sleep.stop
41
42
  @thread.join if @thread
42
43
  end
43
44
 
@@ -46,10 +47,12 @@ module Rpush
46
47
  begin
47
48
  connection = Rpush::Daemon::TcpConnection.new(@app, @host, @port)
48
49
  connection.connect
50
+ tuple = connection.read(TUPLE_BYTES)
49
51
 
50
- while tuple = connection.read(TUPLE_BYTES)
52
+ while tuple
51
53
  timestamp, device_token = parse_tuple(tuple)
52
54
  create_feedback(timestamp, device_token)
55
+ tuple = connection.read(TUPLE_BYTES)
53
56
  end
54
57
  rescue StandardError => e
55
58
  log_error(e)
@@ -13,20 +13,18 @@ module Rpush
13
13
 
14
14
  def self.enqueue(notifications)
15
15
  notifications.group_by(&:app_id).each do |app_id, group|
16
- batch = Batch.new(group)
17
- if app = runners[app_id]
18
- app.enqueue(batch)
19
- else
20
- Rpush.logger.error("No such app '#{app_id}' for notifications #{batch.describe}.")
21
- end
16
+ sync_app_with_id(app_id) unless runners[app_id]
17
+ runners[app_id].enqueue(group) if runners[app_id]
22
18
  end
19
+ ProcTitle.update
23
20
  end
24
21
 
25
22
  def self.sync
26
- apps = Rpush::App.all
23
+ apps = Rpush::Daemon.store.all_apps
27
24
  apps.each { |app| sync_app(app) }
28
25
  removed = runners.keys - apps.map(&:id)
29
26
  removed.each { |app_id| runners.delete(app_id).stop }
27
+ ProcTitle.update
30
28
  end
31
29
 
32
30
  def self.sync_app(app)
@@ -35,8 +33,8 @@ module Rpush
35
33
  else
36
34
  runner = new(app)
37
35
  begin
38
- runner.start
39
36
  runners[app.id] = runner
37
+ runner.start
40
38
  rescue StandardError => e
41
39
  Rpush.logger.error("[#{app.name}] Exception raised during startup. Notifications will not be delivered for this app.")
42
40
  Rpush.logger.error(e)
@@ -45,25 +43,28 @@ module Rpush
45
43
  end
46
44
  end
47
45
 
46
+ def self.sync_app_with_id(app_id)
47
+ sync_app(Rpush::Daemon.store.app(app_id))
48
+ end
49
+
48
50
  def self.stop
49
51
  runners.values.map(&:stop)
50
52
  runners.clear
51
53
  end
52
54
 
53
- def self.debug
54
- runners.values.map(&:debug)
55
+ def self.num_dispatchers
56
+ runners.values.sum(&:num_dispatcher_loops)
55
57
  end
56
58
 
57
- def self.idle
58
- runners.values.select(&:idle?)
59
+ def self.num_queued
60
+ runners.values.sum(&:queue_size)
59
61
  end
60
62
 
61
- def self.wait
62
- sleep 0.1 while !runners.values.all?(&:idle?)
63
+ def self.debug
64
+ runners.values.map(&:debug)
63
65
  end
64
66
 
65
67
  attr_reader :app
66
- attr_accessor :batch
67
68
 
68
69
  def initialize(app)
69
70
  @app = app
@@ -71,27 +72,40 @@ module Rpush
71
72
  end
72
73
 
73
74
  def start
74
- app.connections.times { dispatchers.push(new_dispatcher_loop) }
75
+ app.connections.times { dispatcher_loops.push(new_dispatcher_loop) }
75
76
  start_loops
76
77
  log_info("Started, #{dispatchers_str}.")
77
78
  end
78
79
 
79
80
  def stop
80
- dispatchers.stop
81
+ wait_until_idle
82
+ stop_dispatcher_loops
81
83
  stop_loops
82
84
  end
83
85
 
84
- def enqueue(batch)
85
- self.batch = batch
86
- batch.notifications.each do |notification|
87
- queue.push([notification, batch])
88
- reflect(:notification_enqueued, notification)
86
+ def wait_until_idle
87
+ sleep 0.5 while queue.size > 0
88
+ end
89
+
90
+ def enqueue(notifications)
91
+ if service.batch_deliveries?
92
+ batch_size = (notifications.size / num_dispatcher_loops).ceil
93
+ notifications.in_groups_of(batch_size, false).each do |batch_notifications|
94
+ batch = Batch.new(batch_notifications)
95
+ queue.push(QueuePayload.new(batch))
96
+ end
97
+ else
98
+ batch = Batch.new(notifications)
99
+ notifications.each do |notification|
100
+ queue.push(QueuePayload.new(batch, notification))
101
+ reflect(:notification_enqueued, notification)
102
+ end
89
103
  end
90
104
  end
91
105
 
92
106
  def sync(app)
93
107
  @app = app
94
- diff = dispatchers.size - app.connections
108
+ diff = dispatcher_loops.size - app.connections
95
109
  return if diff == 0
96
110
  if diff > 0
97
111
  decrement_dispatchers(diff)
@@ -103,53 +117,41 @@ module Rpush
103
117
  end
104
118
 
105
119
  def decrement_dispatchers(num)
106
- num.times { dispatchers.pop }
120
+ num.times { dispatcher_loops.pop }
107
121
  end
108
122
 
109
123
  def increment_dispatchers(num)
110
- num.times { dispatchers.push(new_dispatcher_loop) }
124
+ num.times { dispatcher_loops.push(new_dispatcher_loop) }
111
125
  end
112
126
 
113
127
  def debug
114
- Rpush.logger.info <<-EOS
115
-
116
- #{@app.name}:
117
- dispatchers: #{num_dispatchers}
118
- queued: #{queue_size}
119
- batch size: #{batch_size}
120
- batch processed: #{batch_processed}
121
- idle: #{idle?}
122
- EOS
123
- end
128
+ dispatcher_details = {}
129
+
130
+ dispatcher_loops.loops.each_with_index do |dispatcher_loop, i|
131
+ dispatcher_details[i] = {
132
+ started_at: dispatcher_loop.started_at.iso8601,
133
+ dispatched: dispatcher_loop.dispatch_count,
134
+ thread_status: dispatcher_loop.thread_status
135
+ }
136
+ end
124
137
 
125
- def idle?
126
- batch ? batch.complete? : true
138
+ runner_details = { dispatchers: dispatcher_details, queued: queue_size }
139
+ log_info(JSON.pretty_generate(runner_details))
127
140
  end
128
141
 
129
142
  def queue_size
130
143
  queue.size
131
144
  end
132
145
 
133
- def batch_size
134
- batch ? batch.num_notifications : 0
135
- end
136
-
137
- def batch_processed
138
- batch ? batch.num_processed : 0
139
- end
140
-
141
- def num_dispatchers
142
- dispatchers.size
146
+ def num_dispatcher_loops
147
+ dispatcher_loops.size
143
148
  end
144
149
 
145
- protected
150
+ private
146
151
 
147
152
  def start_loops
148
- service_module.loops.each do |loop_class|
149
- instance = loop_class.new(@app)
150
- instance.start
151
- @loops << instance
152
- end
153
+ @loops = service.loop_instances(@app)
154
+ @loops.map(&:start)
153
155
  end
154
156
 
155
157
  def stop_loops
@@ -157,27 +159,32 @@ module Rpush
157
159
  @loops = []
158
160
  end
159
161
 
162
+ def stop_dispatcher_loops
163
+ dispatcher_loops.stop
164
+ @dispatcher_loops = nil
165
+ end
166
+
160
167
  def new_dispatcher_loop
161
- dispatcher = service_module.new_dispatcher(@app)
168
+ dispatcher = service.new_dispatcher(@app)
162
169
  dispatcher_loop = Rpush::Daemon::DispatcherLoop.new(queue, dispatcher)
163
170
  dispatcher_loop.start
164
171
  dispatcher_loop
165
172
  end
166
173
 
167
- def service_module
168
- return @service_module if defined? @service_module
169
- @service_module = "Rpush::Daemon::#{@app.service_name.camelize}".constantize
174
+ def service
175
+ return @service if defined? @service
176
+ @service = "Rpush::Daemon::#{@app.service_name.camelize}".constantize
170
177
  end
171
178
 
172
179
  def queue
173
180
  @queue ||= Queue.new
174
181
  end
175
182
 
176
- def dispatchers
177
- @dispatchers ||= Rpush::Daemon::DispatcherLoopCollection.new
183
+ def dispatcher_loops
184
+ @dispatcher_loops ||= Rpush::Daemon::DispatcherLoopCollection.new
178
185
  end
179
186
 
180
- def dispatchers_str(count = app.connections)
187
+ def dispatchers_str(count = num_dispatcher_loops)
181
188
  count = count.abs
182
189
  str = count == 1 ? 'dispatcher' : 'dispatchers'
183
190
  "#{count} #{str}"
@@ -3,8 +3,7 @@ module Rpush
3
3
  class Batch
4
4
  include Reflectable
5
5
 
6
- attr_reader :num_processed, :notifications,
7
- :delivered, :failed, :retryable
6
+ attr_reader :num_processed, :notifications, :delivered, :failed, :retryable
8
7
 
9
8
  def initialize(notifications)
10
9
  @notifications = notifications
@@ -15,61 +14,80 @@ module Rpush
15
14
  @mutex = Mutex.new
16
15
  end
17
16
 
18
- def num_notifications
19
- @notifications.size
17
+ def complete?
18
+ @complete == true
19
+ end
20
+
21
+ def each_notification(&blk)
22
+ @notifications.each(&blk)
23
+ end
24
+
25
+ def each_delivered(&blk)
26
+ @delivered.each(&blk)
20
27
  end
21
28
 
22
29
  def mark_retryable(notification, deliver_after)
23
- if Rpush.config.batch_storage_updates
24
- retryable[deliver_after] ||= []
25
- retryable[deliver_after] << notification
26
- Rpush::Daemon.store.mark_retryable(notification, deliver_after, :persist => false)
27
- else
28
- Rpush::Daemon.store.mark_retryable(notification, deliver_after)
29
- reflect(:notification_will_retry, notification)
30
+ @mutex.synchronize do
31
+ @retryable[deliver_after] ||= []
32
+ @retryable[deliver_after] << notification
30
33
  end
34
+ Rpush::Daemon.store.mark_retryable(notification, deliver_after, persist: false)
31
35
  end
32
36
 
33
37
  def mark_delivered(notification)
34
- if Rpush.config.batch_storage_updates
35
- delivered << notification
36
- Rpush::Daemon.store.mark_delivered(notification, Time.now, :persist => false)
37
- else
38
- Rpush::Daemon.store.mark_delivered(notification, Time.now)
39
- reflect(:notification_delivered, notification)
38
+ @mutex.synchronize do
39
+ @delivered << notification
40
+ end
41
+ Rpush::Daemon.store.mark_delivered(notification, Time.now, persist: false)
42
+ end
43
+
44
+ def mark_all_delivered
45
+ @mutex.synchronize do
46
+ @delivered = @notifications
47
+ end
48
+ each_notification do |notification|
49
+ Rpush::Daemon.store.mark_delivered(notification, Time.now, persist: false)
40
50
  end
41
51
  end
42
52
 
43
53
  def mark_failed(notification, code, description)
44
- if Rpush.config.batch_storage_updates
45
- key = [code, description]
46
- failed[key] ||= []
47
- failed[key] << notification
48
- Rpush::Daemon.store.mark_failed(notification, code, description, Time.now, :persist => false)
49
- else
50
- Rpush::Daemon.store.mark_failed(notification, code, description, Time.now)
51
- reflect(:notification_failed, notification)
54
+ key = [code, description]
55
+ @mutex.synchronize do
56
+ @failed[key] ||= []
57
+ @failed[key] << notification
52
58
  end
59
+ Rpush::Daemon.store.mark_failed(notification, code, description, Time.now, persist: false)
53
60
  end
54
61
 
55
- def notification_dispatched
62
+ def mark_all_failed(code, message)
63
+ key = [code, message]
56
64
  @mutex.synchronize do
57
- @num_processed += 1
58
- complete if @num_processed >= @notifications.size
65
+ @failed[key] = @notifications
66
+ end
67
+ each_notification do |notification|
68
+ Rpush::Daemon.store.mark_failed(notification, code, message, Time.now, persist: false)
59
69
  end
60
70
  end
61
71
 
62
- def complete?
63
- @complete == true
72
+ def notification_processed
73
+ @mutex.synchronize do
74
+ @num_processed += 1
75
+ complete if @num_processed >= @notifications.size
76
+ end
64
77
  end
65
78
 
66
- def describe
67
- notifications.map(&:id).join(', ')
79
+ def all_processed
80
+ @mutex.synchronize do
81
+ @num_processed = @notifications.size
82
+ complete
83
+ end
68
84
  end
69
85
 
70
86
  private
71
87
 
72
88
  def complete
89
+ return if complete?
90
+
73
91
  [:complete_delivered, :complete_failed, :complete_retried].each do |method|
74
92
  begin
75
93
  send(method)
@@ -79,36 +97,32 @@ module Rpush
79
97
  end
80
98
  end
81
99
 
82
- notifications.clear
83
100
  @complete = true
84
101
  end
85
102
 
86
103
  def complete_delivered
87
- Rpush::Daemon.store.mark_batch_delivered(delivered)
88
- delivered.each do |notification|
104
+ Rpush::Daemon.store.mark_batch_delivered(@delivered)
105
+ @delivered.each do |notification|
89
106
  reflect(:notification_delivered, notification)
90
107
  end
91
- delivered.clear
92
108
  end
93
109
 
94
110
  def complete_failed
95
- failed.each do |(code, description), notifications|
111
+ @failed.each do |(code, description), notifications|
96
112
  Rpush::Daemon.store.mark_batch_failed(notifications, code, description)
97
113
  notifications.each do |notification|
98
114
  reflect(:notification_failed, notification)
99
115
  end
100
116
  end
101
- failed.clear
102
117
  end
103
118
 
104
119
  def complete_retried
105
- retryable.each do |deliver_after, notifications|
120
+ @retryable.each do |deliver_after, notifications|
106
121
  Rpush::Daemon.store.mark_batch_retryable(notifications, deliver_after)
107
122
  notifications.each do |notification|
108
123
  reflect(:notification_will_retry, notification)
109
124
  end
110
125
  end
111
- retryable.clear
112
126
  end
113
127
  end
114
128
  end