Allow dynamic lookup of APNS authentication keys via topics
See original GitHub issueWe have built a platform that provides many applications with a variety of services. For APNS connections we’ve been using Pushy with great results.
Since we are a platform with constant uptime, new applications are registered dynamically. Any application that needs to pass information to APNS will provide us with the required keys and topics during registration. This brings me to the configuration challenge we have with Pushy.
Problem Outline
Pushy, currently, requires that all topics are registered with their associated token before a message can be sent to that topic. For single application systems, or even multiple application systems with a finite set of applications, this is a simple and practical approach. For our platform this configuration requirement is a bit of a nuisance and doesn’t make the best use of resources.
Here’s an example explaining some of the problems. First, an application is registered with our platform and APNS topics and keys are provided. The application is used for testing for a few times then left idle for a period of time (say until the next time testing is done). With Pushy currently we must pre-register the topics and keys for the new application so they are ready when APNS communication is attempted; this could be registered “eagerly” when the application is registered or “lazily” when the first attempt to communicate with APNS about the specified topic is made. If/when the application is unregistered we can unregister the topics and keys from Pushy. So far, no problem, but when the application is left idle and unused it’s now consuming resources (memory for keys, topics & CPU as the ApnsRegistry grows in size). As the number of applications registered grows so does our resource usage. This is essentially the “memory leak via infinite caching” problem.
The only solution, currently, is to test the ApnsRegistry to see if the topic is registered then call into Pushy normally; essentially lazy registration. Unfortunately, nothing currently exists to handle the case of unregistering topics/tokens. There is no way to introspect the ApnsRegistry and do cache pruning based on LRU or other methods.
Proposed Solution
Now that the problem description is, hopefully, outlined well here’s my suggested solution (this is built upon the code in #404)
Replace ApnsRegistry
in the ApnsClientHandler
with a simple interface for locating an ApnsKey
for a specific topic; e.g. ApnsKeyLocator
. That coupled with some method of providing a specific implementation of ApnsKeyLocator
to the ApnsClientHandler
would allow users to match implementations to their usage.
I can think of 3 implementations people might need:
ApnsKeyRegistry
: A synchronized locator that can be shared between handlers; the registry name implies pre-registered keys. (i.e. the current method)ApnsConcurrentKeyRegistry
: A locator that manages oneApnsKeyRegistry
per handler (eschewing locking). (i.e. the method proposed)ApnsOnDemandLocator
: A locator that dynamically looks up keys as they are requested. An implementation based on the GuavaLoadingCache
is imagined.
To be implemented most flexibly you would need two interfaces:
ApnsKeyLocator
: The interfaceApnsClientHandler
uses to locate keys for specific topics.ApnsKeyLocatorFactory
: The interface provided toApnsClient
used to create aApnsKeyLocator
for each new handler.
Proposed interfaces for the above:
interface ApnsKeyLocator {
/*
Looks up an ApnsKey for a given topic.
Providing the ApnsClientHandler during locating allows implementations to
optimize based on the individual handler (e.g. for concurrency).
*/
ApnsKey locate(ApnsClientHandler handler, String topic);
}
interface ApnsKeyLocatorFactory {
/*
Creates, shares or recycles an ApnsKeyLocator for the handler.
Not sure these parameters are necessary, or even useful, for actual implementations
but erring on the side of flexibility and providing as much context as possible.
*/
ApnsKeyLocator create(ApnsClient client, ApnsClientHandler handler);
}
For “compatibility” you could make ApnsClient
which would work with nothing but ApnsKeyLocatorFactory
and be the most flexible implementation. A SimpleApnsClient
would manage an internal ApnsKeyRegistery
(imagined above); providing all the same key registration methods ApnsClient
currently does.
Issue Analytics
- State:
- Created 7 years ago
- Comments:11 (7 by maintainers)
Top GitHub Comments
Much appreciated. Let’s get the connection pooling stuff settled out first, though, just in case that dredges up some shocking architectural revelations that would make things difficult here.
Sadly, I think we have to shelve this for now. It turns out that the intended behavior is “one team per connection.” I think that means that the whole registry pattern is basically crazy at this point, and we should plan on just binding a single key to a connection.