Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce SQS connection pooling #52

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Conversation

linkyndy
Copy link
Contributor

@linkyndy linkyndy commented Jan 24, 2020

Everytime a new Aws::SQS::Client is instantiated, requests to retrieve SQS credentials are triggered. Since this happens for merely every Sqewer.submit! and derivates, a lot of SQS credential requests are fired, leading to quite a big slowdown.

Here's a small test run with connection pooling:

/app # bundle console
irb(main):001:0> require'./app'
=> true
irb(main):002:0> Net::HTTP.class_eval do alias original_request request; def request(request, body = nil, &block); puts "#{request.method} #{use_ssl? ? "https" : "http"}://#{request["host"] || address}"; original_request(request, body, &block) end end
=> :request
irb(main):004:0> Sqewer.submit!(Job.new(data: 'test'))
GET http://169.254.169.254
GET http://169.254.169.254
POST https://sqs.eu-west-1.amazonaws.com
=> nil
irb(main):005:0> Sqewer.submit!(Job.new(data: 'test'))
POST https://sqs.eu-west-1.amazonaws.com
=> nil
irb(main):006:0> Sqewer.submit!(Job.new(data: 'test'))
POST https://sqs.eu-west-1.amazonaws.com
=> nil
irb(main):007:0> Sqewer.submit!(Job.new(data: 'test'))
POST https://sqs.eu-west-1.amazonaws.com
=> nil

and without connection pooling:

/app # bundle console
irb(main):001:0> require'./app'
=> true
irb(main):002:2" Net::HTTP.class_eval do alias original_request request; def request(request, body = nil, &block); puts "#{request.method} #{use_ssl? ? "https" : "http"}://#{request["host"] || address}"; original_request(request, body, &block) end end
=> :request
irb(main):004:0> Sqewer.submit!(Job.new(data: 'test'))
GET http://169.254.169.254
GET http://169.254.169.254
POST https://sqs.eu-west-1.amazonaws.com
=> nil
irb(main):005:0> Sqewer.submit!(Job.new(data: 'test'))
GET http://169.254.169.254
GET http://169.254.169.254
POST https://sqs.eu-west-1.amazonaws.com
=> nil
irb(main):006:0> Sqewer.submit!(Job.new(data: 'test'))
GET http://169.254.169.254
GET http://169.254.169.254
POST https://sqs.eu-west-1.amazonaws.com
=> nil
irb(main):007:0> Sqewer.submit!(Job.new(data: 'test'))
GET http://169.254.169.254
GET http://169.254.169.254
POST https://sqs.eu-west-1.amazonaws.com
=> nil

We basically start an app console, perform some meta-magic on Net::HTTP to print requests that are being made and then fire a few Sqewer.submit!. You can observe two GET requests to http://169.254.169.254 happening for every submit where connection pooling is not used.

With this PR, there will be a default connection pool available, the same as there was previously a default connection available. The connection pool can also be injected to Sqewer, in a similar way to how a connection would have been previously injected.

@linkyndy linkyndy changed the title Initial attempt at connection pooling Introduce SQS connection pooling Feb 13, 2020
@linkyndy linkyndy requested a review from julik February 13, 2020 15:42
@linkyndy linkyndy marked this pull request as ready for review February 19, 2020 12:28
Copy link
Contributor

@julik julik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually looks very good, see minor suggestions above. 🚀 🚀

@@ -1,3 +1,5 @@
require 'connection_pool'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need to require connection_pool or depend on it - we can provide a NullPool instead (Prorate gem has a similar setup). Less dependencies that way :-) and if we document connection_pool compatibility people may install it themselves

@@ -24,6 +26,18 @@ def self.submit!(*jobs, **options)
Sqewer::Submitter.default.submit!(*jobs, **options)
end

def self.default_connection_pool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we create an accessor pair (client_pool / client_pool=) instead, to adhere by the principle of least surprise? We can then also return a NullPool from the reader if nothing was configured

@@ -21,7 +21,13 @@ def submit!(job, **kwargs_for_send)
else
serializer.serialize(job)
end
connection.send_message(message_body, **kwargs_for_send)
if connection_pool.is_a?(Sqewer::ConnectionMessagebox)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use a pool always, but with a stand-in NullPool when none is configured?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit trickier, because the message box also uses a connection (it acts as a composed object). Given the API around this, this is the best solution I found. If you have something better in mind, I'd be happy to make it work :)

@@ -28,6 +28,7 @@
client.delete_queue(queue_url: ENV.fetch('SQS_QUEUE_URL')) rescue Aws::SQS::Errors::NonExistentQueue

ENV.delete('SQS_QUEUE_URL')
Sqewer.reset_default_connection_pool!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have an accessor pair we could do an explicit assignment here instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants