rapns 3.3.2 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/README.md +19 -21
- data/bin/rapns +14 -13
- data/lib/generators/templates/rapns.rb +8 -4
- data/lib/rapns.rb +7 -0
- data/lib/rapns/TODO +3 -0
- data/lib/rapns/apns/feedback.rb +4 -2
- data/lib/rapns/app.rb +3 -1
- data/lib/rapns/configuration.rb +8 -1
- data/lib/rapns/daemon.rb +3 -1
- data/lib/rapns/daemon/apns/app_runner.rb +3 -2
- data/lib/rapns/daemon/apns/certificate_expired_error.rb +20 -0
- data/lib/rapns/daemon/apns/connection.rb +26 -0
- data/lib/rapns/daemon/apns/delivery.rb +2 -1
- data/lib/rapns/daemon/apns/delivery_handler.rb +2 -2
- data/lib/rapns/daemon/app_runner.rb +50 -28
- data/lib/rapns/daemon/batch.rb +100 -0
- data/lib/rapns/daemon/delivery.rb +6 -10
- data/lib/rapns/daemon/delivery_handler.rb +14 -12
- data/lib/rapns/daemon/delivery_handler_collection.rb +33 -0
- data/lib/rapns/daemon/feeder.rb +3 -5
- data/lib/rapns/daemon/gcm/delivery.rb +5 -4
- data/lib/rapns/daemon/gcm/delivery_handler.rb +2 -2
- data/lib/rapns/daemon/store/active_record.rb +23 -2
- data/lib/rapns/deprecation.rb +7 -6
- data/lib/rapns/logger.rb +1 -1
- data/lib/rapns/notification.rb +5 -3
- data/lib/rapns/reflection.rb +1 -1
- data/lib/rapns/version.rb +1 -1
- data/lib/tasks/cane.rake +1 -1
- data/lib/tasks/test.rake +8 -3
- data/spec/unit/apns/app_spec.rb +4 -4
- data/spec/unit/apns_feedback_spec.rb +1 -1
- data/spec/unit/configuration_spec.rb +12 -6
- data/spec/unit/daemon/apns/app_runner_spec.rb +6 -4
- data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
- data/spec/unit/daemon/apns/connection_spec.rb +46 -10
- data/spec/unit/daemon/apns/delivery_handler_spec.rb +24 -18
- data/spec/unit/daemon/apns/delivery_spec.rb +11 -12
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +16 -16
- data/spec/unit/daemon/app_runner_shared.rb +27 -10
- data/spec/unit/daemon/app_runner_spec.rb +48 -28
- data/spec/unit/daemon/batch_spec.rb +160 -0
- data/spec/unit/daemon/delivery_handler_collection_spec.rb +37 -0
- data/spec/unit/daemon/delivery_handler_shared.rb +20 -11
- data/spec/unit/daemon/feeder_spec.rb +12 -12
- data/spec/unit/daemon/gcm/app_runner_spec.rb +4 -2
- data/spec/unit/daemon/gcm/delivery_handler_spec.rb +18 -10
- data/spec/unit/daemon/gcm/delivery_spec.rb +47 -17
- data/spec/unit/daemon/interruptible_sleep_spec.rb +3 -3
- data/spec/unit/daemon/reflectable_spec.rb +1 -1
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +1 -1
- data/spec/unit/daemon/store/active_record_spec.rb +87 -10
- data/spec/unit/daemon_spec.rb +6 -6
- data/spec/unit/deprecation_spec.rb +2 -2
- data/spec/unit/logger_spec.rb +33 -17
- data/spec/unit/notification_shared.rb +7 -3
- data/spec/unit/upgraded_spec.rb +8 -14
- data/spec/unit_spec_helper.rb +9 -1
- metadata +57 -76
- data/lib/rapns/daemon/delivery_queue.rb +0 -42
- data/lib/rapns/daemon/delivery_queue_18.rb +0 -44
- data/lib/rapns/daemon/delivery_queue_19.rb +0 -42
- data/spec/acceptance/gcm_upgrade_spec.rb +0 -34
- data/spec/acceptance_spec_helper.rb +0 -85
- data/spec/unit/daemon/delivery_queue_spec.rb +0 -29
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c28537d83dadc2e500819f9c5ad87e9893de09ac
|
4
|
+
data.tar.gz: b7eadda9453403f8bd159467a15917ff0c9fa913
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 25d3e207864ca02a1c3dc6b037d0548b88cf1025cf12f3fae3c50c3f821c4dcb328e389496dd6d7faa26acb4a47460be2cf751950c1ec66ee07220bd92c8bfaf
|
7
|
+
data.tar.gz: 505315d930cc146ce3fc83f5f3497003bf7b7bfdbc2a0a387ff7017a3ec51b7955ba9bf7285dc781000cf259d99dc4143989af6da15e74032d08cfd00e4f1fe6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
### 3.4.0 (Aug 28, 2013)
|
2
|
+
* Rails 4 support.
|
3
|
+
* Add apns_certificate_will_expire reflection.
|
4
|
+
* Perform storage update in batches where possible, to increase throughput.
|
5
|
+
* airbrake_notify is now deprecated, use the Reflection API instead.
|
6
|
+
* Fix calling the notification_delivered reflection twice (#149).
|
7
|
+
|
1
8
|
## 3.3.2 (June 30, 2013)
|
2
9
|
* Fix Rails 3.0.x compatibility (#138) (@yoppi).
|
3
10
|
* Ensure Rails does not set a default value for text columns (#137).
|
data/README.md
CHANGED
@@ -4,19 +4,16 @@
|
|
4
4
|
### Rapns - Professional grade APNs and GCM for Ruby.
|
5
5
|
|
6
6
|
* Supports both APNs (iOS) and GCM (Google Cloud Messaging, Android).
|
7
|
-
* Seamless Rails integration.
|
8
|
-
* Scalable - choose the number of
|
7
|
+
* Seamless Rails (3, 4) integration.
|
8
|
+
* Scalable - choose the number of persistent connections for each app.
|
9
9
|
* Designed for uptime - signal -HUP to add, update apps.
|
10
10
|
* Stable - reconnects database and network connections when lost.
|
11
|
-
* Run as a daemon or inside an existing
|
11
|
+
* Run as a daemon or inside an [existing processs](https://github.com/ileitch/rapns/wiki/Embedding-API).
|
12
12
|
* Use in a scheduler for low-workload deployments ([Push API](https://github.com/ileitch/rapns/wiki/Push-API)).
|
13
|
-
* Reflection API for fine-grained instrumentation ([Reflection API](https://github.com/ileitch/rapns/wiki/
|
13
|
+
* Reflection API for fine-grained instrumentation and error handling ([Reflection API](https://github.com/ileitch/rapns/wiki/Reflection-API)).
|
14
14
|
* Works with MRI, JRuby, Rubinius 1.8 and 1.9.
|
15
|
-
* [Airbrake](http://airbrakeapp.com/) integration.
|
16
15
|
* Built with love.
|
17
16
|
|
18
|
-
#### 2.x users please read [upgrading from 2.x to 3.0](https://github.com/ileitch/rapns/wiki/Upgrading-from-version-2.x-to-3.0)
|
19
|
-
|
20
17
|
### Who uses Rapns?
|
21
18
|
|
22
19
|
[GateGuru](http://gateguruapp.com) and [Desk.com](http://desk.com), among others!
|
@@ -34,7 +31,7 @@ Generate the migrations, rapns.yml and migrate:
|
|
34
31
|
rails g rapns
|
35
32
|
rake db:migrate
|
36
33
|
|
37
|
-
## Create an App
|
34
|
+
## Create an App & Notification
|
38
35
|
|
39
36
|
#### APNs
|
40
37
|
|
@@ -44,24 +41,12 @@ If this is your first time using the APNs, you will need to generate SSL certifi
|
|
44
41
|
app = Rapns::Apns::App.new
|
45
42
|
app.name = "ios_app"
|
46
43
|
app.certificate = File.read("/path/to/sandbox.pem")
|
47
|
-
app.environment = "sandbox"
|
44
|
+
app.environment = "sandbox" # APNs environment.
|
48
45
|
app.password = "certificate password"
|
49
46
|
app.connections = 1
|
50
47
|
app.save!
|
51
48
|
```
|
52
49
|
|
53
|
-
#### GCM
|
54
|
-
```ruby
|
55
|
-
app = Rapns::Gcm::App.new
|
56
|
-
app.name = "android_app"
|
57
|
-
app.auth_key = "..."
|
58
|
-
app.connections = 1
|
59
|
-
app.save!
|
60
|
-
```
|
61
|
-
|
62
|
-
## Create a Notification
|
63
|
-
|
64
|
-
#### APNs
|
65
50
|
```ruby
|
66
51
|
n = Rapns::Apns::Notification.new
|
67
52
|
n.app = Rapns::Apns::App.find_by_name("ios_app")
|
@@ -71,7 +56,18 @@ n.attributes_for_device = {:foo => :bar}
|
|
71
56
|
n.save!
|
72
57
|
```
|
73
58
|
|
59
|
+
You should also implement the [apns_certificate_will_expire](https://github.com/ileitch/rapns/wiki/Reflection-API) reflection to monitor when your certificate is due to expire.
|
60
|
+
|
74
61
|
#### GCM
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
app = Rapns::Gcm::App.new
|
65
|
+
app.name = "android_app"
|
66
|
+
app.auth_key = "..."
|
67
|
+
app.connections = 1
|
68
|
+
app.save!
|
69
|
+
```
|
70
|
+
|
75
71
|
```ruby
|
76
72
|
n = Rapns::Gcm::Notification.new
|
77
73
|
n.app = Rapns::Gcm::App.find_by_name("android_app")
|
@@ -80,6 +76,8 @@ n.data = {:message => "hi mom!"}
|
|
80
76
|
n.save!
|
81
77
|
```
|
82
78
|
|
79
|
+
GCM also requires you to respond to [Canonical IDs](https://github.com/ileitch/rapns/wiki/Canonical-IDs).
|
80
|
+
|
83
81
|
## Starting Rapns
|
84
82
|
|
85
83
|
As a daemon:
|
data/bin/rapns
CHANGED
@@ -5,28 +5,29 @@ require 'rapns'
|
|
5
5
|
|
6
6
|
environment = ARGV[0]
|
7
7
|
|
8
|
-
banner = 'Usage: rapns <Rails environment> [options]'
|
9
|
-
if environment.nil? || environment =~ /^-/
|
10
|
-
puts banner
|
11
|
-
exit 1
|
12
|
-
end
|
13
|
-
|
14
8
|
config = Rapns::ConfigurationWithoutDefaults.new
|
15
9
|
|
16
|
-
ARGV.options do |opts|
|
17
|
-
opts.banner =
|
10
|
+
options = ARGV.options do |opts|
|
11
|
+
opts.banner = 'Usage: rapns <Rails environment> [options]'
|
18
12
|
opts.on('-f', '--foreground', 'Run in the foreground.') { config.foreground = true }
|
19
|
-
opts.on('-P N', '--db-poll N', Integer, "Frequency in seconds to check for new notifications.
|
20
|
-
opts.on('-F N', '--feedback-poll N', Integer, "Frequency in seconds to check for feedback.
|
13
|
+
opts.on('-P N', '--db-poll N', Integer, "Frequency in seconds to check for new notifications.") { |n| config.push_poll = n }
|
14
|
+
opts.on('-F N', '--feedback-poll N', Integer, "Frequency in seconds to check for feedback.") { |n| config.feedback_poll = n }
|
21
15
|
opts.on('-e', '--no-error-checks', 'Disable APNs error checking after notification delivery.') { config.check_for_errors = false }
|
22
16
|
opts.on('-n', '--no-airbrake-notify', 'Disables error notifications via Airbrake.') { config.airbrake_notify = false }
|
23
17
|
opts.on('-p PATH', '--pid-file PATH', String, 'Path to write PID file. Relative to Rails root unless absolute.') { |path| config.pid_file = path }
|
24
|
-
opts.on('-b N', '--batch-size N', Integer, '
|
25
|
-
opts.on('-
|
18
|
+
opts.on('-b N', '--batch-size N', Integer, 'Storage backend notification batch size.') { |n| config.batch_size = n }
|
19
|
+
opts.on('-B', '--[no-]batch-storage-updates', 'Perform storage updates in batches.') { |v| config.batch_storage_updates = v }
|
20
|
+
opts.on('-v', '--version', 'Print the version.') { puts "rapns #{Rapns::VERSION}"; exit }
|
26
21
|
opts.on('-h', '--help', 'You\'re looking at it.') { puts opts; exit }
|
27
|
-
opts.parse!
|
28
22
|
end
|
29
23
|
|
24
|
+
if environment.nil? || environment =~ /^-/
|
25
|
+
puts options.to_s
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
options.parse!
|
30
|
+
|
30
31
|
ENV['RAILS_ENV'] = environment
|
31
32
|
load 'config/environment.rb'
|
32
33
|
load 'config/initializers/rapns.rb' if File.exist?('config/initializers/rapns.rb')
|
@@ -11,15 +11,15 @@
|
|
11
11
|
# Frequency in seconds to check for feedback
|
12
12
|
# config.feedback_poll = 60
|
13
13
|
|
14
|
-
# Enable/Disable error notifications via Airbrake.
|
15
|
-
# config.airbrake_notify = true
|
16
|
-
|
17
14
|
# Disable APNs error checking after notification delivery.
|
18
15
|
# config.check_for_errors = true
|
19
16
|
|
20
17
|
# ActiveRecord notifications batch size.
|
21
18
|
# config.batch_size = 5000
|
22
19
|
|
20
|
+
# Perform updates to the storage backend in batches to reduce IO.
|
21
|
+
# config.batch_storage_updates = true
|
22
|
+
|
23
23
|
# Path to write PID file. Relative to Rails root unless absolute.
|
24
24
|
# config.pid_file = '/path/to/rapns.pid'
|
25
25
|
|
@@ -71,8 +71,12 @@ Rapns.reflect do |on|
|
|
71
71
|
# on.gcm_canonical_id do |old_id, canonical_id|
|
72
72
|
# end
|
73
73
|
|
74
|
+
# Called when an APNs certificate will expire within 1 month.
|
75
|
+
# Implement on.error to catch errors raised when the certificate expires.
|
76
|
+
# on.apns_certificate_will_expire do |app, expiration_time|
|
77
|
+
# end
|
78
|
+
|
74
79
|
# Called when an exception is raised.
|
75
80
|
# on.error do |error|
|
76
81
|
# end
|
77
|
-
|
78
82
|
end
|
data/lib/rapns.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'multi_json'
|
3
3
|
|
4
|
+
module Rapns
|
5
|
+
def self.attr_accessible_available?
|
6
|
+
require 'rails'
|
7
|
+
::Rails::VERSION::STRING < '4'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
require 'rapns/version'
|
5
12
|
require 'rapns/deprecation'
|
6
13
|
require 'rapns/deprecatable'
|
data/lib/rapns/TODO
ADDED
data/lib/rapns/apns/feedback.rb
CHANGED
@@ -3,7 +3,9 @@ module Rapns
|
|
3
3
|
class Feedback < ActiveRecord::Base
|
4
4
|
self.table_name = 'rapns_feedback'
|
5
5
|
|
6
|
-
|
6
|
+
if Rapns.attr_accessible_available?
|
7
|
+
attr_accessible :device_token, :failed_at, :app
|
8
|
+
end
|
7
9
|
|
8
10
|
validates :device_token, :presence => true
|
9
11
|
validates :failed_at, :presence => true
|
@@ -11,4 +13,4 @@ module Rapns
|
|
11
13
|
validates_with Rapns::Apns::DeviceTokenFormatValidator
|
12
14
|
end
|
13
15
|
end
|
14
|
-
end
|
16
|
+
end
|
data/lib/rapns/app.rb
CHANGED
@@ -2,7 +2,9 @@ module Rapns
|
|
2
2
|
class App < ActiveRecord::Base
|
3
3
|
self.table_name = 'rapns_apps'
|
4
4
|
|
5
|
-
|
5
|
+
if Rapns.attr_accessible_available?
|
6
|
+
attr_accessible :name, :environment, :certificate, :password, :connections, :auth_key
|
7
|
+
end
|
6
8
|
|
7
9
|
has_many :notifications, :class_name => 'Rapns::Notification'
|
8
10
|
|
data/lib/rapns/configuration.rb
CHANGED
@@ -9,7 +9,7 @@ module Rapns
|
|
9
9
|
|
10
10
|
CONFIG_ATTRS = [:foreground, :push_poll, :feedback_poll, :embedded,
|
11
11
|
:airbrake_notify, :check_for_errors, :pid_file, :batch_size,
|
12
|
-
:push, :store, :logger]
|
12
|
+
:push, :store, :logger, :batch_storage_updates]
|
13
13
|
|
14
14
|
class ConfigurationWithoutDefaults < Struct.new(*CONFIG_ATTRS)
|
15
15
|
end
|
@@ -31,6 +31,11 @@ module Rapns
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
def airbrake_notify=(bool)
|
35
|
+
Rapns::Deprecation.warn("airbrake_notify is deprecated. Please use the Rapns.reflect API instead.")
|
36
|
+
super(bool)
|
37
|
+
end
|
38
|
+
|
34
39
|
def pid_file=(path)
|
35
40
|
if path && !Pathname.new(path).absolute?
|
36
41
|
super(File.join(Rails.root, path))
|
@@ -67,6 +72,7 @@ module Rapns
|
|
67
72
|
|
68
73
|
self.push_poll = 2
|
69
74
|
self.feedback_poll = 60
|
75
|
+
Rapns::Deprecation.muted { self.airbrake_notify = true }
|
70
76
|
self.airbrake_notify = true
|
71
77
|
self.check_for_errors = true
|
72
78
|
self.batch_size = 5000
|
@@ -74,6 +80,7 @@ module Rapns
|
|
74
80
|
self.apns_feedback_callback = nil
|
75
81
|
self.store = :active_record
|
76
82
|
self.logger = nil
|
83
|
+
self.batch_storage_updates = true
|
77
84
|
|
78
85
|
# Internal options.
|
79
86
|
self.embedded = false
|
data/lib/rapns/daemon.rb
CHANGED
@@ -9,13 +9,15 @@ require 'rapns/daemon/reflectable'
|
|
9
9
|
require 'rapns/daemon/interruptible_sleep'
|
10
10
|
require 'rapns/daemon/delivery_error'
|
11
11
|
require 'rapns/daemon/delivery'
|
12
|
-
require 'rapns/daemon/delivery_queue'
|
13
12
|
require 'rapns/daemon/feeder'
|
13
|
+
require 'rapns/daemon/batch'
|
14
14
|
require 'rapns/daemon/app_runner'
|
15
15
|
require 'rapns/daemon/delivery_handler'
|
16
|
+
require 'rapns/daemon/delivery_handler_collection'
|
16
17
|
|
17
18
|
require 'rapns/daemon/apns/delivery'
|
18
19
|
require 'rapns/daemon/apns/disconnection_error'
|
20
|
+
require 'rapns/daemon/apns/certificate_expired_error'
|
19
21
|
require 'rapns/daemon/apns/connection'
|
20
22
|
require 'rapns/daemon/apns/app_runner'
|
21
23
|
require 'rapns/daemon/apns/delivery_handler'
|
@@ -2,9 +2,10 @@ module Rapns
|
|
2
2
|
module Daemon
|
3
3
|
module Apns
|
4
4
|
class AppRunner < Rapns::Daemon::AppRunner
|
5
|
+
|
5
6
|
protected
|
6
7
|
|
7
|
-
def
|
8
|
+
def after_start
|
8
9
|
unless Rapns.config.push
|
9
10
|
poll = Rapns.config.feedback_poll
|
10
11
|
@feedback_receiver = FeedbackReceiver.new(app, poll)
|
@@ -12,7 +13,7 @@ module Rapns
|
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
+
def after_stop
|
16
17
|
@feedback_receiver.stop if @feedback_receiver
|
17
18
|
end
|
18
19
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rapns
|
2
|
+
module Apns
|
3
|
+
class CertificateExpiredError < StandardError
|
4
|
+
attr_reader :app, :time
|
5
|
+
|
6
|
+
def initialize(app, time)
|
7
|
+
@app = app
|
8
|
+
@time = time
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
message
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
"#{app.name} certificate expired at #{time}."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -101,6 +101,8 @@ module Rapns
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def connect_socket
|
104
|
+
check_certificate_expiration
|
105
|
+
|
104
106
|
tcp_socket = TCPSocket.new(@host, @port)
|
105
107
|
tcp_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, 1)
|
106
108
|
tcp_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
@@ -110,6 +112,30 @@ module Rapns
|
|
110
112
|
Rapns.logger.info("[#{@app.name}] Connected to #{@host}:#{@port}")
|
111
113
|
[tcp_socket, ssl_socket]
|
112
114
|
end
|
115
|
+
|
116
|
+
def check_certificate_expiration
|
117
|
+
cert = @ssl_context.cert
|
118
|
+
if certificate_expired?
|
119
|
+
Rapns.logger.error(certificate_msg('expired'))
|
120
|
+
raise Rapns::Apns::CertificateExpiredError.new(@app, cert.not_after)
|
121
|
+
elsif certificate_expires_soon?
|
122
|
+
Rapns.logger.warn(certificate_msg('will expire'))
|
123
|
+
reflect(:apns_certificate_will_expire, @app, cert.not_after)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def certificate_msg(msg)
|
128
|
+
time = @ssl_context.cert.not_after.utc.strftime("%Y-%m-%d %H:%M:%S %Z")
|
129
|
+
"[#{@app.name}] Certificate #{msg} at #{time}."
|
130
|
+
end
|
131
|
+
|
132
|
+
def certificate_expired?
|
133
|
+
@ssl_context.cert.not_after && @ssl_context.cert.not_after.utc < Time.now.utc
|
134
|
+
end
|
135
|
+
|
136
|
+
def certificate_expires_soon?
|
137
|
+
@ssl_context.cert.not_after && @ssl_context.cert.not_after.utc < (Time.now + 1.month).utc
|
138
|
+
end
|
113
139
|
end
|
114
140
|
end
|
115
141
|
end
|
@@ -16,10 +16,11 @@ module Rapns
|
|
16
16
|
255 => "None (unknown error)"
|
17
17
|
}
|
18
18
|
|
19
|
-
def initialize(app, conneciton, notification)
|
19
|
+
def initialize(app, conneciton, notification, batch)
|
20
20
|
@app = app
|
21
21
|
@connection = conneciton
|
22
22
|
@notification = notification
|
23
|
+
@batch = batch
|
23
24
|
end
|
24
25
|
|
25
26
|
def perform
|
@@ -13,8 +13,8 @@ module Rapns
|
|
13
13
|
@host, @port = HOSTS[@app.environment.to_sym]
|
14
14
|
end
|
15
15
|
|
16
|
-
def deliver(notification)
|
17
|
-
Rapns::Daemon::Apns::Delivery.
|
16
|
+
def deliver(notification, batch)
|
17
|
+
Rapns::Daemon::Apns::Delivery.new(@app, connection, notification, batch).perform
|
18
18
|
end
|
19
19
|
|
20
20
|
def stopped
|
@@ -1,17 +1,23 @@
|
|
1
1
|
module Rapns
|
2
2
|
module Daemon
|
3
3
|
class AppRunner
|
4
|
+
extend Reflectable
|
5
|
+
include Reflectable
|
6
|
+
|
4
7
|
class << self
|
5
8
|
attr_reader :runners
|
6
9
|
end
|
7
10
|
|
8
11
|
@runners = {}
|
9
12
|
|
10
|
-
def self.enqueue(
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
def self.enqueue(notifications)
|
14
|
+
notifications.group_by(&:app_id).each do |app_id, group|
|
15
|
+
batch = Batch.new(group)
|
16
|
+
if app = runners[app_id]
|
17
|
+
app.enqueue(batch)
|
18
|
+
else
|
19
|
+
Rapns.logger.error("No such app '#{app_id}' for notifications #{batch.describe}.")
|
20
|
+
end
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
@@ -33,6 +39,7 @@ module Rapns
|
|
33
39
|
rescue StandardError => e
|
34
40
|
Rapns.logger.error("[#{app.name}] Exception raised during startup. Notifications will not be delivered for this app.")
|
35
41
|
Rapns.logger.error(e)
|
42
|
+
reflect(:error, e)
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
@@ -60,31 +67,36 @@ module Rapns
|
|
60
67
|
end
|
61
68
|
|
62
69
|
attr_reader :app
|
70
|
+
attr_accessor :batch
|
63
71
|
|
64
72
|
def initialize(app)
|
65
73
|
@app = app
|
66
74
|
end
|
67
75
|
|
68
|
-
def
|
69
|
-
end
|
70
|
-
|
71
|
-
def
|
72
|
-
end
|
76
|
+
def before_start; end
|
77
|
+
def after_start; end
|
78
|
+
def before_stop; end
|
79
|
+
def after_stop; end
|
73
80
|
|
74
81
|
def start
|
75
|
-
|
76
|
-
|
82
|
+
before_start
|
83
|
+
app.connections.times { handlers.push(start_handler) }
|
84
|
+
after_start
|
77
85
|
Rapns.logger.info("[#{app.name}] Started, #{handlers_str}.")
|
78
86
|
end
|
79
87
|
|
80
88
|
def stop
|
81
|
-
|
82
|
-
|
83
|
-
|
89
|
+
before_stop
|
90
|
+
handlers.stop
|
91
|
+
after_stop
|
84
92
|
end
|
85
93
|
|
86
|
-
def enqueue(
|
87
|
-
|
94
|
+
def enqueue(batch)
|
95
|
+
self.batch = batch
|
96
|
+
batch.notifications.each do |notification|
|
97
|
+
queue.push([notification, batch])
|
98
|
+
reflect(:notification_enqueued, notification)
|
99
|
+
end
|
88
100
|
end
|
89
101
|
|
90
102
|
def sync(app)
|
@@ -92,20 +104,20 @@ module Rapns
|
|
92
104
|
diff = handlers.size - app.connections
|
93
105
|
return if diff == 0
|
94
106
|
if diff > 0
|
95
|
-
diff
|
96
|
-
Rapns.logger.info("[#{app.name}] Stopped #{handlers_str(diff)}. #{handlers_str}
|
107
|
+
decrement_handlers(diff)
|
108
|
+
Rapns.logger.info("[#{app.name}] Stopped #{handlers_str(diff)}. #{handlers_str} running.")
|
97
109
|
else
|
98
|
-
diff.abs
|
99
|
-
Rapns.logger.info("[#{app.name}] Started #{handlers_str(diff)}. #{handlers_str}
|
110
|
+
increment_handlers(diff.abs)
|
111
|
+
Rapns.logger.info("[#{app.name}] Started #{handlers_str(diff)}. #{handlers_str} running.")
|
100
112
|
end
|
101
113
|
end
|
102
114
|
|
103
|
-
def decrement_handlers
|
104
|
-
handlers.pop
|
115
|
+
def decrement_handlers(num)
|
116
|
+
num.times { handlers.pop }
|
105
117
|
end
|
106
118
|
|
107
|
-
def increment_handlers
|
108
|
-
|
119
|
+
def increment_handlers(num)
|
120
|
+
num.times { handlers.push(start_handler) }
|
109
121
|
end
|
110
122
|
|
111
123
|
def debug
|
@@ -114,18 +126,28 @@ module Rapns
|
|
114
126
|
#{@app.name}:
|
115
127
|
handlers: #{num_handlers}
|
116
128
|
queued: #{queue_size}
|
129
|
+
batch size: #{batch_size}
|
130
|
+
batch processed: #{batch_processed}
|
117
131
|
idle: #{idle?}
|
118
132
|
EOS
|
119
133
|
end
|
120
134
|
|
121
135
|
def idle?
|
122
|
-
|
136
|
+
batch ? batch.complete? : true
|
123
137
|
end
|
124
138
|
|
125
139
|
def queue_size
|
126
140
|
queue.size
|
127
141
|
end
|
128
142
|
|
143
|
+
def batch_size
|
144
|
+
batch ? batch.num_notifications : 0
|
145
|
+
end
|
146
|
+
|
147
|
+
def batch_processed
|
148
|
+
batch ? batch.num_processed : 0
|
149
|
+
end
|
150
|
+
|
129
151
|
def num_handlers
|
130
152
|
handlers.size
|
131
153
|
end
|
@@ -140,11 +162,11 @@ module Rapns
|
|
140
162
|
end
|
141
163
|
|
142
164
|
def queue
|
143
|
-
@queue ||=
|
165
|
+
@queue ||= Queue.new
|
144
166
|
end
|
145
167
|
|
146
168
|
def handlers
|
147
|
-
@
|
169
|
+
@handlers ||= Rapns::Daemon::DeliveryHandlerCollection.new
|
148
170
|
end
|
149
171
|
|
150
172
|
def handlers_str(count = app.connections)
|