sqs_buffer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 67e3a29c2cf4c0bf644d388fef3c67c55435be20
4
+ data.tar.gz: ac1d17611aa8d095b175af1baf8747ceb4007ae8
5
+ SHA512:
6
+ metadata.gz: e9371ad563ff830c44e1e6963d250d5010116da3438d6fa2d406310aafce466391afac6dcdda6c16e51e0abd2c4343f06fd1839d7ecd51f06069b80f25147bc5
7
+ data.tar.gz: 18d1580ff5a425b4db944cb68cc8db138bb97c9281006de39a739225c33dc4337f91145ca6adb5c2a683a024ba11d181b30ef572c406030e802c61744ccaf6d9
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ jruby-1.7.19
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sqs_buffer.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 John Thomas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # SqsBuffer
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sqs_buffer`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'sqs_buffer'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install sqs_buffer
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( https://github.com/[my-github-username]/sqs_buffer/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sqs_buffer"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,157 @@
1
+ require 'thread'
2
+ require 'aws-sdk'
3
+ require 'concurrent'
4
+
5
+ module SqsBuffer
6
+ class Client
7
+ def initialize(opts)
8
+ @queue_url = opts.fetch(:queue_url) { |k| missing_key!(k) }
9
+ client = opts.fetch(:client) { |k| missing_key!(k) }
10
+
11
+ @poller = Aws::SQS::QueuePoller.new(@queue_url, client: client)
12
+ @skip_delete = opts.fetch(:skip_delete, true)
13
+ @max_number_of_messages = opts.fetch(:max_number_of_messages, 10)
14
+ @logger = opts.fetch(:logger, Logger.new(STDOUT))
15
+ @process_block = Concurrent::MutexAtomicReference.new
16
+ @before_request_block = Concurrent::MutexAtomicReference.new
17
+ @process_block = Concurrent::MutexAtomicReference.new
18
+ @message_queue = Concurrent::Array.new
19
+ @last_process_time = Concurrent::AtomicFixnum.new(Time.now.to_i)
20
+ @running = Concurrent::AtomicBoolean.new(false)
21
+ @max_wait_time = Concurrent::AtomicFixnum.new(
22
+ opts.fetch(:max_wait_time, 300)
23
+ )
24
+ @max_queue_threshold = Concurrent::AtomicFixnum.new(
25
+ opts.fetch(:max_queue_threshold, 100)
26
+ )
27
+ configure_before_request_block
28
+ end
29
+
30
+ def start_polling
31
+ @running.make_true
32
+
33
+ @worker_thread = Thread.new do
34
+ opts = {
35
+ skip_delete: @skip_delete,
36
+ max_number_of_messages: @max_number_of_messages
37
+ }
38
+ @poller.poll(opts) do |messages|
39
+ store_messages(messages)
40
+ end
41
+ end # End worker thread
42
+
43
+ @running.value
44
+ end
45
+
46
+ def queue_url
47
+ @queue_url
48
+ end
49
+
50
+ def stop_polling
51
+ @running.make_false
52
+ end
53
+
54
+ def queue_full?
55
+ @message_queue.length >= @max_queue_threshold.value
56
+ end
57
+
58
+ def queue_empty?
59
+ @message_queue.empty?
60
+ end
61
+
62
+ def queue_length
63
+ @message_queue.length
64
+ end
65
+
66
+ def shutting_down?
67
+ @running.false? && worker_thread_alive?
68
+ end
69
+
70
+ def running?
71
+ @running.true? && worker_thread_alive?
72
+ end
73
+
74
+ def worker_thread_alive?
75
+ !@worker_thread.nil? && @worker.alive?
76
+ end
77
+
78
+ def last_process_time_stale?
79
+ @last_process_time.value < Time.now.to_i - @max_wait_time.value
80
+ end
81
+
82
+ def process_all_messages
83
+ # This will be a collection of SQS messages
84
+ # I am pretty sure this exposes the @message_queue to mutability
85
+ # Maybe I should deep dup this?
86
+ @process_block.value.call(@message_queue)
87
+ delete_all_messages
88
+ touch_process_time
89
+ rescue StandardError => e
90
+ @logger.error "An exception(#{e.message}) occurred while process the message queue: #{@message_queue.join("\n")} | Backtrace: #{e.backtrace}"
91
+ end
92
+
93
+ def process_block(&block)
94
+ @process_block.value = block
95
+ end
96
+
97
+ def before_request_block(&block)
98
+ @before_request_block.value = block
99
+ end
100
+
101
+ private
102
+
103
+ def need_to_process?
104
+ if !queue_empty? && (queue_full? || last_process_time_stale?)
105
+ true
106
+ else
107
+ false
108
+ end
109
+ end
110
+
111
+ def missing_key!(k)
112
+ raise ":#{k} is a required key!"
113
+ end
114
+
115
+ def configure_before_request_block
116
+ @poller.before_request do |stats|
117
+ if @running.false?
118
+ @logger.info "Shutting down. Processing all messages first..."
119
+ process_all_messages
120
+ @logger.info "All messages have been processed. Throwing :stop_polling"
121
+ throw :stop_polling
122
+ end
123
+ if @before_request_block.value
124
+ @before_request_block.value.call(stats)
125
+ end
126
+ if need_to_process?
127
+ process_all_messages
128
+ end
129
+ end # End Poller loop
130
+ end
131
+
132
+ def store_messages(messages)
133
+ messages.each do |msg|
134
+ store_message(msg)
135
+ end
136
+ end
137
+
138
+ def store_message(msg)
139
+ @message_queue << msg
140
+ rescue StandardError => e
141
+ @logger.error "Exception: #{e.message} while storing message: #{msg} | Backtrace: #{e.backtrace}"
142
+ end
143
+
144
+ def touch_process_time
145
+ @last_process_time.value = Time.now.to_i
146
+ end
147
+
148
+ def delete_all_messages
149
+ while @message_queue.length > 0 do
150
+ messages = @message_queue.shift(10)
151
+ @poller.delete_messages(messages)
152
+ end
153
+ end
154
+
155
+ end
156
+ end
157
+
@@ -0,0 +1,3 @@
1
+ module SqsBuffer
2
+ VERSION = "0.1.0"
3
+ end
data/lib/sqs_buffer.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "sqs_buffer/version"
2
+ require "sqs_buffer/client"
3
+
4
+ module SqsBuffer
5
+ end
6
+
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sqs_buffer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sqs_buffer"
8
+ spec.version = SqsBuffer::VERSION
9
+ spec.authors = ["John Thomas"]
10
+ spec.email = ["thomas07@vt.edu"]
11
+
12
+ spec.summary = %q{Buffer SQS messages to process more than 10 events}
13
+ spec.description = %q{SQS only allows you to pull and delete 10 events
14
+ at a time. This gem is greedy and will buffer events so you can process
15
+ more than 10 at at time.}
16
+ spec.homepage = "https://github.com/thomas07vt/sqs_buffer.git"
17
+ spec.license = "MIT"
18
+
19
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
20
+ # delete this section to allow pushing this gem to any host.
21
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "aws-sdk", "~> 2.2"
27
+ spec.add_dependency "concurrent-ruby", "~> 1.0"
28
+
29
+ spec.add_development_dependency "bundler"
30
+ spec.add_development_dependency "rake"
31
+ spec.add_development_dependency "rspec"
32
+ spec.add_development_dependency "pry"
33
+ end
34
+
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sqs_buffer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Thomas
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-01-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ~>
17
+ - !ruby/object:Gem::Version
18
+ version: '2.2'
19
+ name: aws-sdk
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.2'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
+ name: concurrent-ruby
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: bundler
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ name: rake
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ name: rspec
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ name: pry
90
+ prerelease: false
91
+ type: :development
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: |-
98
+ SQS only allows you to pull and delete 10 events
99
+ at a time. This gem is greedy and will buffer events so you can process
100
+ more than 10 at at time.
101
+ email:
102
+ - thomas07@vt.edu
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - .gitignore
108
+ - .rspec
109
+ - .ruby-version
110
+ - .travis.yml
111
+ - Gemfile
112
+ - LICENSE.txt
113
+ - README.md
114
+ - Rakefile
115
+ - bin/console
116
+ - bin/setup
117
+ - lib/sqs_buffer.rb
118
+ - lib/sqs_buffer/client.rb
119
+ - lib/sqs_buffer/version.rb
120
+ - sqs_buffer.gemspec
121
+ homepage: https://github.com/thomas07vt/sqs_buffer.git
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.4.5
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Buffer SQS messages to process more than 10 events
145
+ test_files: []