Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Prevent failed connection from stopping the daemon - see Issue #62 #70

Merged
merged 9 commits into from

2 participants

@mattconnolly

Prevent failed connection from stopping the daemon - see Issue #62.

There's a few other small adjustments in this pull request too:

  • Updated deprecated rspec expects
  • Moved database test configuration into a config file instead of hard coded.
  • refactored a variable name to better reflect the content of the variable.
config/database.yml
@@ -0,0 +1,31 @@
+# postgresql is the default if no ADAPTER environment variable is set when running specs.
+
+postgresql:
+ adapter: postgresql
+ database: postgres
@ileitch Owner
ileitch added a note

database should be rapns_test for all adapters. Also leave username blank in here as it is set explicitly in the spec_helper. This should fix the CI failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mattconnolly

I just updated the database name. The postgresql username is still overridden when the TRAVIS environment variable is set in spec_helper.rb as before.

@mattconnolly

spec_helper only overrides the username in jruby, not in ruby 1.8/1.9.

also, is there a way I can trigger the travis ci build? or is it automagically done by github?

@ileitch ileitch merged commit e676a19 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 9, 2012
  1. @mattconnolly

    Making database configuration driven by rails-like .yml file instead …

    mattconnolly authored
    …of being hard coded in spec_helper.rb
  2. @mattconnolly
Commits on Sep 10, 2012
  1. @mattconnolly
  2. @mattconnolly

    Improvements to stop Daemon from exiting when a connection fails (Issue

    mattconnolly authored
    #62):
    
    * AppRunner excludes apps that fail to start
    * FeedbackReceiver thread will end cleanly if a connection fails with an SSL error
    * Connection logs failed connection attempts as well as successful ones
  3. @mattconnolly
Commits on Sep 11, 2012
  1. @mattconnolly
  2. @mattconnolly
  3. @mattconnolly
  4. @mattconnolly
This page is out of date. Refresh to see the latest.
View
3  README.md
@@ -164,4 +164,5 @@ Thank you to the following wonderful people for contributing to rapns:
* [@tompesman](https://github.com/tompesman)
* [@EpicDraws](https://github.com/EpicDraws)
* [@dei79](https://github.com/dei79)
-* [@adorr](https://github.com/adorr)
+* [@adorr](https://github.com/adorr)
+* [@mattconnolly](https://github.com/mattconnolly)
View
31 config/database.yml
@@ -0,0 +1,31 @@
+# postgresql is the default if no ADAPTER environment variable is set when running specs.
+
+postgresql:
+ adapter: postgresql
+ database: rapns_test
+ host: localhost
+ username: postgres
+ password: ""
+
+jdbcpostgresql:
+ adapter: jdbcpostgresql
+ database: rapns_test
+ host: localhost
+ username: postgres
+ password: ""
+
+mysql:
+ adapter: mysql
+ database: rapns_test
+ host: localhost
+ username: rapns_test
+ password: ""
+ encoding: utf8
+
+mysql2:
+ adapter: mysql
+ database: rapns_test
+ host: localhost
+ username: rapns_test
+ password: ""
+ encoding: utf8
View
24 lib/rapns/daemon/app_runner.rb
@@ -42,8 +42,12 @@ def self.sync
feedback_host, feedback_port = HOSTS[app.environment.to_sym][:feedback]
feedback_poll = Rapns::Daemon.config.feedback_poll
runner = AppRunner.new(app, push_host, push_port, feedback_host, feedback_port, feedback_poll)
- runner.start
- @all[app.key] = runner
+ begin
+ runner.start
+ @all[app.key] = runner
+ rescue
+ Rapns::Daemon.logger.info("[App:#{app.key}] failed to start. No notifications will be sent.")
+ end
end
end
@@ -72,11 +76,19 @@ def initialize(app, push_host, push_port, feedback_host, feedback_port, feedback
@handlers = []
end
- def start
- @feedback_receiver = FeedbackReceiver.new(@app.key, @feedback_host, @feedback_port, @feedback_poll, @app.certificate, @app.password)
- @feedback_receiver.start
- @app.connections.times { @handlers << start_handler }
+ def start
+ begin
+ @feedback_receiver = FeedbackReceiver.new(@app.key, @feedback_host, @feedback_port, @feedback_poll, @app.certificate, @app.password)
+ @feedback_receiver.start
+
+ @app.connections.times { @handlers << start_handler }
+ rescue OpenSSL::SSL::SSLError
+ # these errors mean that a connection is not possible, raise back to caller
+ raise
+ rescue StandardError => e
+ Rapns::Daemon.logger.error(e)
+ end
end
def deliver(notification)
View
3  lib/rapns/daemon/connection.rb
@@ -105,6 +105,9 @@ def connect_socket
ssl_socket.connect
Rapns::Daemon.logger.info("[#{@name}] Connected to #{@host}:#{@port}")
[tcp_socket, ssl_socket]
+ rescue StandardError => e
+ Rapns::Daemon.logger.error("[#{@name}] Error connecting to #{@host}:#{@port} : #{e}")
+ raise
end
end
end
View
24 lib/rapns/daemon/feedback_receiver.rb
@@ -5,8 +5,8 @@ class FeedbackReceiver
FEEDBACK_TUPLE_BYTES = 38
- def initialize(app, host, port, poll, certificate, password)
- @app = app
+ def initialize(name, host, port, poll, certificate, password)
+ @name = name
@host = host
@port = port
@poll = poll
@@ -17,8 +17,17 @@ def initialize(app, host, port, poll, certificate, password)
def start
@thread = Thread.new do
loop do
- break if @stop
- check_for_feedback
+ begin
+ break if @stop
+ check_for_feedback
+ rescue OpenSSL::SSL::SSLError
+ # stop the thread if there is an SSL error. Other errors might be recoverable,
+ # and retrying later might make sense (for example, a network outage)
+ @stop = true
+ break
+ rescue
+ # error will be logged in check_for_feedback
+ end
interruptible_sleep @poll
end
end
@@ -33,7 +42,7 @@ def stop
def check_for_feedback
connection = nil
begin
- connection = Connection.new("FeedbackReceiver:#{@app}", @host, @port, @certificate, @password)
+ connection = Connection.new("FeedbackReceiver:#{@name}", @host, @port, @certificate, @password)
connection.connect
while tuple = connection.read(FEEDBACK_TUPLE_BYTES)
@@ -42,6 +51,7 @@ def check_for_feedback
end
rescue StandardError => e
Rapns::Daemon.logger.error(e)
+ raise
ensure
connection.close if connection
end
@@ -56,8 +66,8 @@ def parse_tuple(tuple)
def create_feedback(failed_at, device_token)
formatted_failed_at = failed_at.strftime("%Y-%m-%d %H:%M:%S UTC")
- Rapns::Daemon.logger.info("[FeedbackReceiver:#{@app}] Delivery failed at #{formatted_failed_at} for #{device_token}")
- Rapns::Feedback.create!(:failed_at => failed_at, :device_token => device_token, :app => @app)
+ Rapns::Daemon.logger.info("[FeedbackReceiver:#{@name}] Delivery failed at #{formatted_failed_at} for #{device_token}")
+ Rapns::Feedback.create!(:failed_at => failed_at, :device_token => device_token, :app => @name)
end
end
end
View
6 rapns.gemspec
@@ -11,9 +11,9 @@ Gem::Specification.new do |s|
s.summary = %q{Easy to use, full featured APNs daemon for Rails 3}
s.description = %q{Easy to use, full featured APNs daemon for Rails 3}
- s.files = `git ls-files lib`.split("\n") + ["README.md", "CHANGELOG.md", "LICENSE"]
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.files = `git ls-files -- lib README.md CHANGELOG.md LICENSE`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features,config}`.split("\n")
+ s.executables = `git ls-files -- bin`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
s.add_dependency "multi_json", "~> 1.0"
View
2  spec/rapns/daemon/connection_spec.rb
@@ -110,7 +110,7 @@
it "ignores IOError when the socket is already closed" do
tcp_socket.stub(:close).and_raise(IOError)
connection.connect
- expect { connection.close }.should_not raise_error(IOError)
+ expect { connection.close }.to_not raise_error(IOError)
end
end
View
2  spec/rapns/daemon/feedback_receiver_spec.rb
@@ -66,7 +66,7 @@ def connection.read(bytes)
error = StandardError.new('bork!')
connection.stub(:read).and_raise(error)
Rapns::Daemon.logger.should_receive(:error).with(error)
- receiever.check_for_feedback
+ lambda { receiever.check_for_feedback }.should raise_error
end
it 'sleeps for the feedback poll period' do
View
2  spec/rapns/notification_spec.rb
@@ -43,7 +43,7 @@
describe Rapns::Notification, "when assigning the attributes for the device" do
it "should raise an ArgumentError if something other than a Hash is assigned" do
- expect { Rapns::Notification.new(:attributes_for_device => Array.new) }.should
+ expect { Rapns::Notification.new(:attributes_for_device => Array.new) }.to \
raise_error(ArgumentError, "attributes_for_device must be a Hash")
end
View
34 spec/spec_helper.rb
@@ -10,37 +10,37 @@
end
require 'active_record'
-adapters = ['mysql', 'mysql2', 'postgresql', 'jdbcpostgresql']
jruby = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
-$adapter = if ENV['ADAPTER']
- ENV['ADAPTER']
-elsif jruby
- 'jdbcpostgresql'
-else
- 'postgresql'
+$adapter = ENV['ADAPTER'] ||
+ if jruby
+ 'jdbcpostgresql'
+ else
+ 'postgresql'
+ end
+
+DATABASE_CONFIG = YAML.load_file(File.expand_path("../config/database.yml", File.dirname(__FILE__)))
+db_config = DATABASE_CONFIG[$adapter]
+
+if db_config.nil?
+ puts "No such adapter '#{$adapter}'. Valid adapters are #{DATABASE_CONFIG.keys.join(', ')}."
+ exit 1
end
if jruby
if ENV['TRAVIS']
- username = 'postgres'
+ db_config['username'] = 'postgres'
else
require 'etc'
- username = Etc.getlogin
+ db_config['username'] = Etc.getlogin
end
-else
- username = nil
-end
-
-if !adapters.include?($adapter)
- puts "No such adapter '#{$adapter}'. Valid adapters are #{adapters.join(', ')}."
- exit 1
end
puts "Using #{$adapter} adapter."
-ActiveRecord::Base.establish_connection('username' => username, 'adapter' => $adapter, 'database' => 'rapns_test')
+ActiveRecord::Base.establish_connection(db_config)
+
require 'generators/templates/create_rapns_notifications'
require 'generators/templates/create_rapns_feedback'
require 'generators/templates/add_alert_is_json_to_rapns_notifications'
Something went wrong with that request. Please try again.