arthropod 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 402aefa5ebb2883aa9660285c850995454a8a5dd87dc5cf4b1fc3131c66a25cc
4
+ data.tar.gz: fb12c70b9088b22e81cac21de40edd01e23fb50b668b8f775010ed80cfdff31b
5
+ SHA512:
6
+ metadata.gz: 2bf3436d18735c33198c163fc950aaca20f663828c6e5cdc918000df26bcf109a1c6abac885c1a96dec22fc42c8a4d0ea64c745165974d3b0a75d4738ed81364
7
+ data.tar.gz: 52a1c6f6b0455633e97414eae5eeadf359b4436aae49653714031f9aba8f023538845c77fc9c9536426a5c749073c99aae67db1225345ee793b3916eb23467d1
@@ -0,0 +1 @@
1
+ .env
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,49 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ arthropod (0.0.1)
5
+ aws-sdk-sqs
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ aws-eventstream (1.0.3)
11
+ aws-partitions (1.251.0)
12
+ aws-sdk-core (3.84.0)
13
+ aws-eventstream (~> 1.0, >= 1.0.2)
14
+ aws-partitions (~> 1, >= 1.239.0)
15
+ aws-sigv4 (~> 1.1)
16
+ jmespath (~> 1.0)
17
+ aws-sdk-sqs (1.23.1)
18
+ aws-sdk-core (~> 3, >= 3.71.0)
19
+ aws-sigv4 (~> 1.1)
20
+ aws-sigv4 (1.1.0)
21
+ aws-eventstream (~> 1.0, >= 1.0.2)
22
+ diff-lcs (1.3)
23
+ jmespath (1.4.0)
24
+ rake (13.0.1)
25
+ rspec (3.9.0)
26
+ rspec-core (~> 3.9.0)
27
+ rspec-expectations (~> 3.9.0)
28
+ rspec-mocks (~> 3.9.0)
29
+ rspec-core (3.9.0)
30
+ rspec-support (~> 3.9.0)
31
+ rspec-expectations (3.9.0)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.9.0)
34
+ rspec-mocks (3.9.0)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.9.0)
37
+ rspec-support (3.9.0)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ arthropod!
44
+ bundler
45
+ rake
46
+ rspec
47
+
48
+ BUNDLED WITH
49
+ 2.0.2
@@ -0,0 +1,92 @@
1
+ # Arthropod
2
+
3
+ Arthropod is a easy way to run remote ruby code synchronously, using Amazon SQS.
4
+
5
+ *Do not use it yet, the API isn't stable at all and it wasn't tested enough on production*
6
+
7
+ ## Usage
8
+
9
+ A simple use case first, let's say you want to push a video encoding task to another server:
10
+
11
+ ```ruby
12
+ url_of_the_video = "https://my_storage.my_service.com/my_video_file.mp4"
13
+ response = Arthropod::Client.push(queue_name: "video_encoding", body: { url: url_of_the_video })
14
+
15
+ puts response.body
16
+ # => "https://my_storage.my_service.com/my_reencoded_video_file.mp4"
17
+ ```
18
+
19
+ On the "server" side:
20
+
21
+ ```ruby
22
+ Arthropod::Server.pull(queue_name: "video_encoding") do |request|
23
+ video_url = request.body.url
24
+
25
+ # Do the encoding stuff
26
+ encoded_video_url = VideoEncoder.encode(video_url)
27
+
28
+ encoded_video_url # Everything evaluated here will be sent back to the client
29
+ end
30
+ ```
31
+
32
+ As you see, it's all synchronous and, since SQS will save your messages until they are consumed, your server doesn't even have to be listening right when you push the task (more on that later).
33
+
34
+ It is also possible to push updates from the server:
35
+
36
+ ```ruby
37
+ Arthropod::Server.pull(queue_name: "video_encoding") do |request|
38
+ video_url = request.body.url
39
+
40
+ # Do the encoding stuff but this time the VideoEncoder class will give you a percentage of completion
41
+ VideoEncoder.encode(video_url) do |percentage_of_completion|
42
+ request.respond { percentage_of_completion: percentage_of_completion }
43
+ end
44
+
45
+ encoded_video_url # Everything evaluated here will be sent back to the client
46
+ end
47
+ ```
48
+
49
+ And on the client side:
50
+
51
+ ```ruby
52
+ url_of_the_video = "https://my_storage.my_service.com/my_video_file.mp4"
53
+ response = Arthropod::Client.push(queue_name: "video_encoding", body: { url: url_of_the_video }) do |response|
54
+ puts response.body.percentage_of_completion # => 10, 20, 30, etc
55
+ end
56
+
57
+ puts response.body
58
+ # => "https://my_storage.my_service.com/my_reencoded_video_file.mp4"
59
+ ```
60
+
61
+ ## API
62
+
63
+ ```ruby
64
+ response = Arthropod::Client.push(queue_name: "video_encoding", body: { url: url_of_the_video }) do |response|
65
+ puts response.body
66
+ end
67
+ ```
68
+
69
+ This method pushes a job to the SQS queue `queue_name` and waits for the job completion, a block can be optionally provided if you expect the server to send you some updates along the way. The return value is the last value evaluated in the server block.
70
+
71
+ ```ruby
72
+ Arthropod::Server.pull(queue_name: "video_encoding") do |request|
73
+ request.respond "some_update"
74
+
75
+ "final_result"
76
+ end
77
+ ```
78
+
79
+ This method will take a job from the queue and give it to the block, if no job are available the method will return immediately, it's your responsiblity to put this call in the loop if you want to. The last value from the block will be sent back to the client.
80
+
81
+ ## Why would you do take an asynchronous thing and make it synchronous?
82
+
83
+ This library is here to solve a few real use-cases we encoutered, most of them involves running heavy tasks on remote servers or on remote computers that are not accessible through the internet. For example:
84
+
85
+ * running some CUDA-related stuff from a cheap server, sometimes it's way cheaper to have a pretty beefy computers in house and run your heavy tasks on them instead of renting one for several hundred dollars each month.
86
+ * sometimes you need to access some data that are only accessible locally, thing about 3D rendering where your assets, cache, etc are all stored locally for better performance. Now your local computer can pull tasks from the SQS queue, run them and push the results.
87
+
88
+ Of course you can also achieve that by simply using SQS or any kind of message system, what Arthropod does is just to make it easier, however it's your responsibilty to run it in an asynchronous environment, think about an ActiveJob task for example. At its core Arthropod is just a thin layer around SQS.
89
+
90
+ ## Example: the poor man's video encoding service
91
+
92
+ If you're not concerned about latency, you can for example push some heavy video encoding task from and ActiveJob job in your Rails task and run a little cron job every minute on your uber-CUDA-powered computer at home to pull those jobs and reencode your videos. It should be reliable enough and it may be even be way faster than doing it with the CPU off a regular server.
@@ -0,0 +1,11 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require "rspec/core/rake_task"
6
+ require "rspec/core/version"
7
+
8
+ desc "Run all examples"
9
+ RSpec::Core::RakeTask.new :spec
10
+
11
+ task default: [:spec]
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "arthropod/version"
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = "arthropod"
9
+ gem.version = Arthropod::VERSION
10
+ gem.authors = ["Victor Goya"]
11
+ gem.email = ["goya.victor@gmail.com"]
12
+ gem.description = "Easy remote task execution with SQS"
13
+ gem.summary = "Execute ruby task on another server synchronously using Amazon SQS"
14
+
15
+ gem.files = `git ls-files -z`.split("\x0")
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.licenses = ["MIT"]
19
+
20
+ gem.add_dependency 'aws-sdk-sqs'
21
+
22
+ gem.required_ruby_version = "~> 2.0"
23
+
24
+ gem.add_development_dependency 'bundler'
25
+ gem.add_development_dependency 'rspec'
26
+ gem.add_development_dependency 'rake'
27
+ end
@@ -0,0 +1,8 @@
1
+ require 'arthropod'
2
+
3
+ loop do
4
+ response = Arthropod::Client.push(queue_name: "my_little_queue", body: { text: gets }) do |response|
5
+ puts "Downcase: #{response.body}"
6
+ end
7
+ puts "Upcase: #{response.body}"
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'arthropod'
2
+
3
+ loop do
4
+ Arthropod::Server.pull(queue_name: "my_little_queue") do |request|
5
+ request.respond request.body["text"].downcase
6
+
7
+ request.body["text"].upcase
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ require 'arthropod/client'
2
+ require 'arthropod/server'
3
+ require 'arthropod/request'
4
+ require 'arthropod/response'
@@ -0,0 +1,34 @@
1
+ require 'aws-sdk-sqs'
2
+ require 'securerandom'
3
+
4
+ module Arthropod
5
+ module Client
6
+ def self.push(queue_name:, body:, client: nil)
7
+ client ||= Aws::SQS::Client.new
8
+
9
+ sender_queue = client.create_queue(queue_name: queue_name)
10
+ return_queue = client.create_queue(queue_name: SecureRandom.uuid.gsub("-", "_"))
11
+
12
+ # Send our order with a return queue so we can get responses
13
+ client.send_message(queue_url: sender_queue.queue_url, message_body: JSON.dump({ return_queue_url: return_queue.queue_url, body: body }))
14
+
15
+ loop do
16
+ response = client.receive_message(queue_url: return_queue.queue_url, max_number_of_messages: 1, wait_time_seconds: 1)
17
+ response.messages.each do |message|
18
+ response = Arthropod::Response.new(client: client, message: message)
19
+ begin
20
+ if response.state == "close"
21
+ return response
22
+ else
23
+ yield response if block_given?
24
+ end
25
+ ensure
26
+ client.delete_message(queue_url: return_queue.queue_url, receipt_handle: message.receipt_handle)
27
+ end
28
+ end
29
+ end
30
+ ensure
31
+ client.delete_queue(queue_url: return_queue.queue_url) if return_queue
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ module Arthropod
2
+ class Request
3
+ attr_reader :message, :client
4
+
5
+ def initialize(client:, message:)
6
+ @client = client
7
+ @message = message
8
+ end
9
+
10
+ def body
11
+ parsed_message_body["body"]
12
+ end
13
+
14
+ def return_queue_url
15
+ parsed_message_body["return_queue_url"]
16
+ end
17
+
18
+ def state
19
+ parsed_message_body["state"]
20
+ end
21
+
22
+ def respond(body = nil)
23
+ send_message({ state: "open", body: body })
24
+ end
25
+
26
+ def close(body = nil)
27
+ send_message({ state: "close", body: body })
28
+ end
29
+
30
+ private
31
+
32
+ def send_message(message_body)
33
+ client.send_message({
34
+ queue_url: return_queue_url,
35
+ message_body: JSON.dump(message_body)
36
+ })
37
+ end
38
+
39
+ def parsed_message_body
40
+ @parsed_message_body ||= JSON.parse(message.body)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ module Arthropod
2
+ class Response
3
+ attr_reader :message, :client
4
+
5
+ def initialize(client:, message:)
6
+ @client = client
7
+ @message = message
8
+ end
9
+
10
+ def body
11
+ parsed_message_body["body"]
12
+ end
13
+
14
+ def state
15
+ parsed_message_body["state"]
16
+ end
17
+
18
+ private
19
+
20
+ def parsed_message_body
21
+ @parsed_message_body ||= JSON.parse(message.body)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'aws-sdk-sqs'
2
+
3
+ module Arthropod
4
+ module Server
5
+ def self.pull(queue_name:, client: nil)
6
+ client ||= Aws::SQS::Client.new
7
+
8
+ sender_queue = client.create_queue(queue_name: queue_name)
9
+ response = client.receive_message(queue_url: sender_queue.queue_url, max_number_of_messages: 1, wait_time_seconds: 1)
10
+ response.messages.each do |message|
11
+ request = Arthropod::Request.new(client: client, message: message)
12
+ begin
13
+ request.close(yield request)
14
+ ensure
15
+ client.delete_message(queue_url: sender_queue.queue_url, receipt_handle: message.receipt_handle)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Arthropod
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,67 @@
1
+ require 'arthropod'
2
+
3
+ RSpec.describe(Arthropod::Client) do
4
+ context "#push" do
5
+ let(:client) do
6
+ Aws::SQS::Client.new(stub_responses: true)
7
+ end
8
+
9
+ let(:sender_queue_url) do
10
+ "https://aws.com/sender_queue_url"
11
+ end
12
+
13
+ let(:return_queue_url) do
14
+ "https://aws.com/return_queue_url"
15
+ end
16
+
17
+ let(:body) do
18
+ { my_key: "my_value" }
19
+ end
20
+
21
+ let(:uuid) do
22
+ "444444444444-4444-4444-8888-88888888"
23
+ end
24
+
25
+ before(:each) do
26
+ expect(SecureRandom).to(
27
+ receive(:uuid)
28
+ .and_return(uuid)
29
+ )
30
+ expect(client).to(
31
+ receive(:create_queue)
32
+ .with({ queue_name: "test" })
33
+ .and_return(OpenStruct.new(queue_url: sender_queue_url))
34
+ )
35
+ expect(client).to(
36
+ receive(:create_queue)
37
+ .with({ queue_name: uuid.gsub("-", "_") })
38
+ .and_return(OpenStruct.new(queue_url: return_queue_url))
39
+ )
40
+ expect(client).to(
41
+ receive(:send_message)
42
+ .with({ queue_url: sender_queue_url, message_body: JSON.dump({ return_queue_url: return_queue_url, body: body }) })
43
+ )
44
+ expect(client).to(
45
+ receive(:receive_message)
46
+ .with({ queue_url: return_queue_url, max_number_of_messages: 1, wait_time_seconds: 1 })
47
+ .and_return(OpenStruct.new(messages: [ OpenStruct.new({ "body" => JSON.dump({ "state" => "open", "body" => "update" }), receipt_handle: "receipt_handle" }) ]))
48
+ )
49
+ expect(client).to(
50
+ receive(:receive_message)
51
+ .with({ queue_url: return_queue_url, max_number_of_messages: 1, wait_time_seconds: 1 })
52
+ .and_return(OpenStruct.new(messages: [ OpenStruct.new({ "body" => JSON.dump({ "state" => "close", "body" => "payload" }), receipt_handle: "receipt_handle" }) ]))
53
+ )
54
+ expect(client).to(
55
+ receive(:delete_queue)
56
+ .with({ queue_url: return_queue_url })
57
+ )
58
+ end
59
+
60
+ it "works" do
61
+ response = Arthropod::Client.push(client: client, queue_name: "test", body: body) do |response|
62
+ expect(response.body).to eq("update")
63
+ end
64
+ expect(response.body).to eq("payload")
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,51 @@
1
+ require 'arthropod'
2
+
3
+ RSpec.describe(Arthropod::Server) do
4
+ context "#pull" do
5
+ let(:client) do
6
+ Aws::SQS::Client.new(stub_responses: true)
7
+ end
8
+
9
+ let(:sender_queue_url) do
10
+ "https://aws.com/sender_queue_url"
11
+ end
12
+
13
+ let(:return_queue_url) do
14
+ "https://aws.com/return_queue_url"
15
+ end
16
+
17
+ let(:uuid) do
18
+ "444444444444-4444-4444-8888-88888888"
19
+ end
20
+
21
+ before(:each) do
22
+ expect(client).to(
23
+ receive(:create_queue)
24
+ .with({ queue_name: "test" })
25
+ .and_return(OpenStruct.new(queue_url: sender_queue_url))
26
+ )
27
+ expect(client).to(
28
+ receive(:receive_message)
29
+ .with({ queue_url: sender_queue_url, max_number_of_messages: 1, wait_time_seconds: 1 })
30
+ .and_return(OpenStruct.new(messages: [ OpenStruct.new({ "body" => JSON.dump({ "body" => "request", "return_queue_url" => return_queue_url }), receipt_handle: "receipt_handle" }) ]))
31
+ )
32
+ expect(client).to(
33
+ receive(:send_message)
34
+ .with({ queue_url: return_queue_url, message_body: JSON.dump({ state: "open", body: "response" }) })
35
+ )
36
+ expect(client).to(
37
+ receive(:send_message)
38
+ .with({ queue_url: return_queue_url, message_body: JSON.dump({ state: "close", body: "final_response" }) })
39
+ )
40
+ end
41
+
42
+ it "works" do
43
+ Arthropod::Server.pull(client: client, queue_name: "test") do |request|
44
+ expect(request.body).to eq("request")
45
+ request.respond "response"
46
+
47
+ "final_response"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,100 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+ RSpec.configure do |config|
17
+ # rspec-expectations config goes here. You can use an alternate
18
+ # assertion/expectation library such as wrong or the stdlib/minitest
19
+ # assertions if you prefer.
20
+ config.expect_with :rspec do |expectations|
21
+ # This option will default to `true` in RSpec 4. It makes the `description`
22
+ # and `failure_message` of custom matchers include text for helper methods
23
+ # defined using `chain`, e.g.:
24
+ # be_bigger_than(2).and_smaller_than(4).description
25
+ # # => "be bigger than 2 and smaller than 4"
26
+ # ...rather than:
27
+ # # => "be bigger than 2"
28
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29
+ end
30
+
31
+ # rspec-mocks config goes here. You can use an alternate test double
32
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
33
+ config.mock_with :rspec do |mocks|
34
+ # Prevents you from mocking or stubbing a method that does not exist on
35
+ # a real object. This is generally recommended, and will default to
36
+ # `true` in RSpec 4.
37
+ mocks.verify_partial_doubles = true
38
+ end
39
+
40
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41
+ # have no way to turn it off -- the option exists only for backwards
42
+ # compatibility in RSpec 3). It causes shared context metadata to be
43
+ # inherited by the metadata hash of host groups and examples, rather than
44
+ # triggering implicit auto-inclusion in groups with matching metadata.
45
+ config.shared_context_metadata_behavior = :apply_to_host_groups
46
+
47
+ # The settings below are suggested to provide a good initial experience
48
+ # with RSpec, but feel free to customize to your heart's content.
49
+ =begin
50
+ # This allows you to limit a spec run to individual examples or groups
51
+ # you care about by tagging them with `:focus` metadata. When nothing
52
+ # is tagged with `:focus`, all examples get run. RSpec also provides
53
+ # aliases for `it`, `describe`, and `context` that include `:focus`
54
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
55
+ config.filter_run_when_matching :focus
56
+
57
+ # Allows RSpec to persist some state between runs in order to support
58
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
59
+ # you configure your source control system to ignore this file.
60
+ config.example_status_persistence_file_path = "spec/examples.txt"
61
+
62
+ # Limits the available syntax to the non-monkey patched syntax that is
63
+ # recommended. For more details, see:
64
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
65
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
67
+ config.disable_monkey_patching!
68
+
69
+ # This setting enables warnings. It's recommended, but in some cases may
70
+ # be too noisy due to issues in dependencies.
71
+ config.warnings = true
72
+
73
+ # Many RSpec users commonly either run the entire suite or an individual
74
+ # file, and it's useful to allow more verbose output when running an
75
+ # individual spec file.
76
+ if config.files_to_run.one?
77
+ # Use the documentation formatter for detailed output,
78
+ # unless a formatter has already been configured
79
+ # (e.g. via a command-line flag).
80
+ config.default_formatter = "doc"
81
+ end
82
+
83
+ # Print the 10 slowest examples and example groups at the
84
+ # end of the spec run, to help surface which specs are running
85
+ # particularly slow.
86
+ config.profile_examples = 10
87
+
88
+ # Run specs in random order to surface order dependencies. If you find an
89
+ # order dependency and want to debug it, you can fix the order by providing
90
+ # the seed, which is printed after each run.
91
+ # --seed 1234
92
+ config.order = :random
93
+
94
+ # Seed global randomization in this process using the `--seed` CLI option.
95
+ # Setting this allows you to use `--seed` to deterministically reproduce
96
+ # test failures related to randomization by passing the same `--seed` value
97
+ # as the one that triggered the failure.
98
+ Kernel.srand config.seed
99
+ =end
100
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: arthropod
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Victor Goya
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-sqs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Easy remote task execution with SQS
70
+ email:
71
+ - goya.victor@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - README.md
81
+ - Rakefile
82
+ - arthropod.gemspec
83
+ - examples/client.rb
84
+ - examples/server.rb
85
+ - lib/arthropod.rb
86
+ - lib/arthropod/client.rb
87
+ - lib/arthropod/request.rb
88
+ - lib/arthropod/response.rb
89
+ - lib/arthropod/server.rb
90
+ - lib/arthropod/version.rb
91
+ - spec/client_spec.rb
92
+ - spec/server_spec.rb
93
+ - spec/spec_helper.rb
94
+ homepage:
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '2.0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubygems_version: 3.0.3
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Execute ruby task on another server synchronously using Amazon SQS
117
+ test_files: []