Hi, I’m Josh Symonds

I blog about Ruby on Rails, coding, and servers

Sidekiq + Houston: Persistent Apple Connection Pooling

Reading time 2 minutes

I updated the code here based on my production experiences with it in a new post, Sidekiq + Houston: Production Ready. Check it out after reading this article.

Having not updated rapnd in a good long while, I was looking for well-supported, up-to-date solution for persisting long-running connections to Apple’s push notification service through a worker. I didn’t run into anything offhand, and also haven’t posted a helpful code snippet in awhile, so this is how I connected Houston and Sidekiq to Apple’s Push Notification service.

From Houston’s documentation, we can easily set up a persistent connection with code like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
uri, certificate = if Rails.env.production?
  [
    Houston::APPLE_PRODUCTION_GATEWAY_URI,
    File.read("/path/to/production_key.pem")
  ]
else
  [
    Houston::APPLE_DEVELOPMENT_GATEWAY_URI,
    File.read("/path/to/development_key.pem")
  ]
end

connection = Houston::Connection.new(uri, certificate, nil)
connection.open

Maintaining a persistent connection pool with Sidekiq workers is easy thanks to Sidekiq’s integration with Connection Pool. We can set that up fairly easily like so:

1
2
3
APN_POOL = ConnectionPool.new(:size => 2, :timeout => 300) do
  # above code
end

I didn’t want more than two connections since that should suffice for initial load; and a timeout of 5 minutes seemed reasonable enough for me. Ultimately, my worker ended up looking like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class NotifierWorker
  include Sidekiq::Worker

  APN_POOL = ConnectionPool.new(:size => 2, :timeout => 300) do
    uri, certificate = if Rails.env.production?
      [
        Houston::APPLE_PRODUCTION_GATEWAY_URI,
        File.read("/path/to/production_key.pem")
      ]
    else
      [
        Houston::APPLE_DEVELOPMENT_GATEWAY_URI,
        File.read("/path/to/development_key.pem")
      ]
    end

    connection = Houston::Connection.new(uri, certificate, nil)
    connection.open

    connection
  end

  def perform(message, token)
    APN_POOL.with do |connection|
      notification = Houston::Notification.new(device: token)
      notification.alert = message
      connection.write(notification.message)
    end
  end

end