Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
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 ileitch:master
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.