dandemeyere/responsys-api — pull request #21 by florrain (2014-12-03 22:46:43+00:00)
Title: Session management

@12and1studio I'd like your comments and review :shipit:
@dandemeyere also if you have a moment to give a quick look would be great :+1:
@evantahler your feedback would be appreciated :eyes:

So. Since we merged in recently a pull request to wrap up all the calls in the client between a login and a logout action, we're experiencing a lot of errors from the API because we're trying to make more calls than our main account is able to. It apparently solved the problem for @evantahler but not for us. Can't really explain it, must be based on our different code infrastructures.

This pull request 's main purpose is to solve all our problems (hopefully). Below is a desc of how we handled it. I'll take our thredUP app as the example to make it more simple to explain.

## Before
We had one `client` as a singleton all over our application. From our perspective the client was used everywhere in the same way: controllers, DJs or Sidekiq jobs. To sum up we have one Sidekiq job which handles our user subscription status and makes a call to the API to update the data regarding the user.

One day we had:
- One singleton
- One job class
- 200,000 jobs waiting/running in the queue trying to reach the API
- A slack channel spammed by a ridiculous number of rollbar errors : `Responsys error - UNEXPECTED_EXCEPTION - Login attempt rejected since it has exceeded the number of concurrent sessions allowed. The maximum number of concurrent sessions allowed : 100`

For sure we weren't expecting it:
[](http://media.giphy.com/media/dxP3suFihnORa/giphy.gif)

## The changes
Important to notice, we don't want to break any existing code. For instance the client is no longer a singleton but works as is.

- `client.rb` : now instanciable. The `.instance` method is still usable though.
The client passes the actions to the `SessionPool`. This is transparent for the user but the client is no longer actually making calls.

- `session_pool.rb` :

The `Responsys::Api::SessionPool` is just the intermediate between the client and the `ConnectionPool` gem. It makes sure the pool is well instanciated with the right params at the first request but then all the calls are passed to the `ConnectionPool`.

[github](https://github.com/mperham/connection_pool) : maintained and [recommended](https://github.com/mperham/sidekiq/wiki/Advanced-Options) by the Sidekiq owner to be used within Sidekiq jobs.

This is the new singleton. It uses the pool gem to make sure we're using a pool of sessions. It must be the only one instance anywhere in the app.
You can quickly read the repo readme to understand the magic but basically it works as a queue of objects :
* You pass the size of the pool in the config params.
* You pass the timeout value in the config params. The timeout represents the time the `ConnectionPool` will wait until a slot is available.
* Each slot in the pool represents one `Responsys::Api::Client::Session` object (a session or socket or connection to the API).
* The pool gets an inactive session or creates a new one if the size hasn't reached the maximum size.
* Each slot is an independent thread. Available when not *run*ning.

- `session.rb` : instanciated by the `SessionPool` to fill it out. All calls are made from this class. This is just mostly a simple copy/paste from the previous client version.

Also updated the tests to keep em green :green_heart:

I had concerns and asked directly on the [repo issue page](https://github.com/mperham/connection_pool/issues/64) which you may be interested in.

Any questions or remarks are very welcome!

Thanks