Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What can cause a connection to APNS to intermittently disconnect?

I've got a ruby script that opens a connection to Apple's push server and sends all the pending notifications. I can't see any reason why, but I get broken pipe errors when Apple disconnects my script. I've written my script to accomodate this happening, but I would rather just find out why it's happening so I can avoid it in the first place.

It doesn't consistently disconnect on a specific notification. It doesn't disconnect at a certain byte transfer size. Everything appears to be sporadic. Are there certain limitations to the data transfer or payload count you can send on a single connection? Seeing people's solutions that hold one connection open all the time, I would assume that isn't the issue. I've seen the connection drop after 3 notifications, and I've seen it drop after 14 notifications. I've never seen it make it past 14.

Has anyone else experienced this type of problem? How can this be handled?

like image 880
Matthew Avatar asked Mar 03 '10 00:03

Matthew


2 Answers

The problem was caused by sending an invalid device token to the APNS server. In this specific case it was a development token. When an invalid device token is sent to APNS, it disconnects the socket. This can cause some headaches, and has been addressed by Apple as being something they are going to address in future updates.

like image 194
Matthew Avatar answered Nov 15 '22 04:11

Matthew


I had the same issue for a bit and did two things to tackle it:

  1. Put some auto-reconnect logic in place: I try to keep my connection for as long as possible but Apple will disconnect you every now and then. Be prepared to handle this.
  2. Move to the enhanced interface: Using the simple interface (that's what the APNS gem and many others use) errors will trigger disconnection without any feedback. If you switch to the enhanced format you will receive an integer back every time something happens. Bad tokens will result in a 8 being returned, and I use this to remove the device from my database.

Here's my current connection code, using EventMachine:

module Apns

  module SocketHandler
    def initialize(wrapper)
      @wrapper = wrapper
    end

    def post_init
      start_tls(:cert_chain_file => @wrapper.pem_path,
                :private_key_file => @wrapper.rsa_path,
                :verify_peer => false)
    end

    def receive_data(data)
      @wrapper.read_data!(data)
    end

    def unbind
      @wrapper.connection_closed!
    end

    def write(data)
      begin
        send_data(data)
      rescue => exc
        @wrapper.connection_error!(exc)
      end
    end

    def close!
      close_connection
    end
  end

  class Connection
    attr_reader :pem_path, :rsa_path

    def initialize(host, port, credentials_path, monitoring, read_data_handler)
      setup_credentials(credentials_path)
      @monitoring = monitoring
      @host = host
      @port = port
      @read_data_handler = read_data_handler
      open_connection!
    end

    def write(data)
      @connection.write(data)
    end

    def open?
      @status == :open
    end

    def connection_closed!
      @status = :closed
    end

    def connection_error!(exception)
      @monitoring.inform_exception!(exception, self)
      @status = :error
    end

    def close!
      @connection.close!
    end

    def read_data!(data)
      @read_data_handler.call(data)
    end

    private
    def setup_credentials(credentials_path)
      @pem_path = "#{credentials_path}.pem"
      @rsa_path = "#{credentials_path}.rsa"
      raise ArgumentError.new("#{credentials_path}.pem and #{credentials_path}.rsa must exist!") unless (File.exists?(@pem_path) and File.exists?(@rsa_path))
    end

    def open_connection!
      @connection = EventMachine.connect(@host, @port, SocketHandler, self)
      @status = :open
    end
  end
end

end end

It separates writes and reads in the connection, using the ID field in the notification to correlated notifications I send with feedback I receive.

like image 34
Phil Calçado Avatar answered Nov 15 '22 03:11

Phil Calçado