sneakers 2.7.0 → 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +7 -6
- data/ChangeLog.md +61 -0
- data/Dockerfile +18 -3
- data/Dockerfile.slim +11 -4
- data/README.md +36 -32
- data/{docker-compose.yaml → docker-compose.yml} +6 -3
- data/lib/sneakers/configuration.rb +0 -1
- data/lib/sneakers/errors.rb +0 -3
- data/lib/sneakers/handlers/maxretry.rb +1 -5
- data/lib/sneakers/handlers/oneshot.rb +0 -4
- data/lib/sneakers/queue.rb +10 -6
- data/lib/sneakers/version.rb +1 -1
- data/lib/sneakers/worker.rb +7 -17
- data/log/.gitkeep +0 -0
- data/sneakers.gemspec +6 -5
- data/spec/sneakers/queue_spec.rb +11 -0
- data/spec/sneakers/runner_spec.rb +2 -2
- data/spec/sneakers/worker_handlers_spec.rb +1 -66
- data/spec/sneakers/worker_spec.rb +13 -62
- data/spec/sneakers/workergroup_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- metadata +37 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b012bf95d1ffd483c544a1e58a11775dd1932726
|
4
|
+
data.tar.gz: 5df9669b11a6870968f08483ae1d4bef08becbeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9875ccd366feeb446faaf1c7d9b2aceb8fd3712aaf67e989329eba05ee4c4dc45e0cc5df718a399eeb7302c924b2d131491db75ce9bb824162ae94a734872889
|
7
|
+
data.tar.gz: 7e6e444e6801cc7ddf4bbbfcd197efe6633cda6f004bce71759414aef978669ae1b29136c9135621fffe4b40986546fe237c9b9dd4d6298862416ff5042f97e1
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -4,14 +4,15 @@ services:
|
|
4
4
|
sudo: false
|
5
5
|
cache: bundler
|
6
6
|
language: ruby
|
7
|
+
before_install:
|
8
|
+
- gem install bundler
|
7
9
|
rvm:
|
8
10
|
- ruby-head
|
9
|
-
- "2.
|
10
|
-
- "2.
|
11
|
-
- "2.
|
11
|
+
- "2.5.1"
|
12
|
+
- "2.4.2"
|
13
|
+
- "2.3.5"
|
14
|
+
- "2.2.8"
|
12
15
|
matrix:
|
13
16
|
include:
|
14
|
-
- rvm: 2.
|
17
|
+
- rvm: 2.4.1
|
15
18
|
env: INTEGRATION_LOG=1 INTEGRATION=1
|
16
|
-
|
17
|
-
|
data/ChangeLog.md
CHANGED
@@ -1,5 +1,66 @@
|
|
1
1
|
# Sneakers Change Log
|
2
2
|
|
3
|
+
## Changes Between 2.10.0 and 2.11.0
|
4
|
+
|
5
|
+
This releases includes bug fixes, support for more queue-binding options, better
|
6
|
+
management of the Bunny dependency, and improved documentation. Following is a
|
7
|
+
list of the notable changes:
|
8
|
+
|
9
|
+
### Rescue from ScriptError
|
10
|
+
|
11
|
+
Fixes a bug that would cause Sneakers workers to freeze if an exception
|
12
|
+
descending from `ScriptError`, such as `NotImplementedError`, is raised
|
13
|
+
|
14
|
+
Contributed by @sharshenov
|
15
|
+
|
16
|
+
GitHub Pull Request: [373](https://github.com/jondot/sneakers/pull/373)
|
17
|
+
|
18
|
+
### Loosen Bunny dependency to minor version
|
19
|
+
|
20
|
+
The dependency on Bunny is now pinned to the minor version instead of patch,
|
21
|
+
allowing users to benefit from non-breaking updates to Bunny without having to
|
22
|
+
wait for a Sneakers release.
|
23
|
+
|
24
|
+
Contributed by @olivierlacan
|
25
|
+
|
26
|
+
GitHub Pull Request: [#372](https://github.com/jondot/sneakers/pull/372)
|
27
|
+
|
28
|
+
### Support `:bind_arguments` on bind
|
29
|
+
|
30
|
+
It is now possible to set arguments on a queue when connecting to a headers
|
31
|
+
exchange
|
32
|
+
|
33
|
+
Contributed by @nerikj
|
34
|
+
|
35
|
+
GitHub Pull Request: [#358](https://github.com/jondot/sneakers/pull/358)
|
36
|
+
|
37
|
+
### Other contributions
|
38
|
+
|
39
|
+
This release also contains contributions from @ivan-kolmychek (bumping up Bunny
|
40
|
+
dependency), @michaelklishin (improving code style), and @darren987469 (adding
|
41
|
+
examples to the README)
|
42
|
+
|
43
|
+
## Changes Between 2.8.0 and 2.10.0
|
44
|
+
|
45
|
+
This release contains **minor breaking API changes**.
|
46
|
+
|
47
|
+
### Worker Timeouts are No Longer Enforced
|
48
|
+
|
49
|
+
This is a **breaking change** for `Sneakers::Worker` implementations.
|
50
|
+
|
51
|
+
Timeouts can be disruptive and dangerous depending on what the workers do but not having them can also
|
52
|
+
lead to operational headaches.
|
53
|
+
|
54
|
+
The outcome of [a lengthy discussion](https://github.com/jondot/sneakers/issues/343) on possible
|
55
|
+
alternatives to the timeout mechanisms is that only applications
|
56
|
+
can know where it is safe to enforce a timeout (and how).
|
57
|
+
|
58
|
+
`Sneakers::Worker` implementations are now expected to enforce timeouts
|
59
|
+
in a way that makes sense (and is safe) to them.
|
60
|
+
|
61
|
+
GitHub issues: [#343](https://github.com/jondot/sneakers/issues/343).
|
62
|
+
|
63
|
+
|
3
64
|
## Changes Between 2.6.0 and 2.7.0
|
4
65
|
|
5
66
|
This release requires Ruby 2.2 and has **breaking API changes**
|
data/Dockerfile
CHANGED
@@ -1,13 +1,28 @@
|
|
1
1
|
FROM ruby:2.3-alpine
|
2
2
|
|
3
3
|
RUN apk add --no-cache git
|
4
|
+
|
4
5
|
RUN apk --update add --virtual build_deps \
|
5
|
-
build-base
|
6
|
-
|
6
|
+
build-base \
|
7
|
+
ruby-dev \
|
8
|
+
libc-dev \
|
9
|
+
linux-headers \
|
10
|
+
openssl-dev
|
11
|
+
|
12
|
+
RUN mkdir /myapp
|
7
13
|
|
8
|
-
ADD . /sneakers
|
9
14
|
WORKDIR /sneakers
|
10
15
|
|
16
|
+
COPY lib/sneakers/version.rb /sneakers/lib/sneakers/version.rb
|
17
|
+
|
18
|
+
COPY sneakers.gemspec /sneakers/sneakers.gemspec
|
19
|
+
|
20
|
+
COPY Gemfile /sneakers/Gemfile
|
21
|
+
|
22
|
+
COPY Gemfile.lock /sneakers/Gemfile.lock
|
23
|
+
|
11
24
|
RUN bundle --jobs=4 --retry=3
|
12
25
|
|
26
|
+
COPY . /sneakers
|
27
|
+
|
13
28
|
CMD rake test
|
data/Dockerfile.slim
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
FROM ruby:2.3-alpine
|
2
2
|
|
3
3
|
RUN apk add --no-cache git
|
4
|
+
|
4
5
|
ADD . /sneakers
|
6
|
+
|
5
7
|
WORKDIR /sneakers
|
6
8
|
|
7
9
|
RUN apk --update add --virtual build_deps \
|
8
|
-
build-base
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
build-base \
|
11
|
+
ruby-dev \
|
12
|
+
libc-dev \
|
13
|
+
linux-headers \
|
14
|
+
openssl-dev && \
|
15
|
+
|
16
|
+
bundle --jobs=4 --retry=3 && \
|
17
|
+
|
18
|
+
apk del build_deps
|
12
19
|
|
13
20
|
CMD rake test
|
data/README.md
CHANGED
@@ -4,47 +4,47 @@
|
|
4
4
|
|
5
5
|
```
|
6
6
|
__
|
7
|
-
,--' >
|
8
|
-
`=====
|
7
|
+
,--' >
|
8
|
+
`=====
|
9
9
|
|
10
10
|
```
|
11
11
|
|
12
|
-
|
13
12
|
A high-performance RabbitMQ background processing framework for
|
14
13
|
Ruby.
|
15
14
|
|
16
|
-
|
17
15
|
Sneakers is being used in production for both I/O and CPU intensive workloads, and have achieved the goals of high-performance and 0-maintenance, as designed.
|
18
16
|
|
19
|
-
|
20
|
-
Visit the [wiki](https://github.com/jondot/sneakers/wiki) for
|
21
|
-
documentation and [GitHub releases](https://github.com/jondot/sneakers/releases) for release
|
22
|
-
notes.
|
23
|
-
|
24
|
-
[![Build Status](https://travis-ci.org/jondot/sneakers.svg?branch=master)](https://travis-ci.org/jondot/sneakers)
|
25
|
-
|
26
|
-
|
27
17
|
## Installation
|
28
18
|
|
29
19
|
Add this line to your application's Gemfile:
|
30
20
|
|
31
|
-
```
|
21
|
+
```ruby
|
32
22
|
gem 'sneakers'
|
33
23
|
```
|
34
24
|
|
35
25
|
And then execute:
|
36
26
|
|
37
|
-
```
|
27
|
+
```shell-session
|
38
28
|
$ bundle
|
39
29
|
```
|
40
30
|
|
41
31
|
Or install it yourself as:
|
42
32
|
|
43
|
-
```
|
33
|
+
```shell-session
|
44
34
|
$ gem install sneakers
|
45
35
|
```
|
46
36
|
|
47
|
-
##
|
37
|
+
## Documentation
|
38
|
+
|
39
|
+
A quick start guide is available in the section below.
|
40
|
+
|
41
|
+
Visit the [wiki](https://github.com/jondot/sneakers/wiki) for more detailed
|
42
|
+
documentation and [GitHub releases](https://github.com/jondot/sneakers/releases) for release
|
43
|
+
notes.
|
44
|
+
|
45
|
+
A [change log](./ChangeLog.md) is also available.
|
46
|
+
|
47
|
+
## Quick start
|
48
48
|
|
49
49
|
Set up a Gemfile
|
50
50
|
|
@@ -60,7 +60,6 @@ then create a worker named as `Processor`.
|
|
60
60
|
|
61
61
|
> touch boot.rb
|
62
62
|
|
63
|
-
|
64
63
|
```ruby
|
65
64
|
require 'sneakers'
|
66
65
|
require 'redis'
|
@@ -86,7 +85,6 @@ end
|
|
86
85
|
|
87
86
|
Let's test it out quickly from the command line:
|
88
87
|
|
89
|
-
|
90
88
|
```shell-session
|
91
89
|
$ sneakers work Processor --require boot.rb
|
92
90
|
```
|
@@ -103,6 +101,20 @@ If you go to your RabbitMQ admin now, you'll see a new queue named `logs` was cr
|
|
103
101
|
}
|
104
102
|
```
|
105
103
|
|
104
|
+
Publish a message with the [bunny](https://github.com/ruby-amqp/bunny) gem RabbitMQ client:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
require 'bunny'
|
108
|
+
|
109
|
+
conn = Bunny.new
|
110
|
+
conn.start
|
111
|
+
|
112
|
+
ch = conn.create_channel
|
113
|
+
ch.default_exchange.publish({ type: 'error', message: 'HALP!', error: 'CODE001' }.to_json, routing_key: 'logs')
|
114
|
+
|
115
|
+
conn.close
|
116
|
+
```
|
117
|
+
|
106
118
|
And this is the output you should see at your terminal.
|
107
119
|
|
108
120
|
```
|
@@ -112,7 +124,6 @@ And this is the output you should see at your terminal.
|
|
112
124
|
2013-10-11T19:26:40Z p-4719 t-ovqgyrx8g INFO: log log
|
113
125
|
```
|
114
126
|
|
115
|
-
|
116
127
|
We'll count errors and error types with Redis.
|
117
128
|
|
118
129
|
``` shell-session
|
@@ -120,11 +131,8 @@ $ redis-cli monitor
|
|
120
131
|
1381520329.888581 [0 127.0.0.1:49182] "incr" "processor:CODE001"
|
121
132
|
```
|
122
133
|
|
123
|
-
|
124
134
|
We're basically done with the ceremonies and all is left is to do some real work.
|
125
135
|
|
126
|
-
|
127
|
-
|
128
136
|
### Looking at metrics
|
129
137
|
|
130
138
|
Let's use the `logging_metrics` provider just for the sake of fun of seeing the metrics as they happen.
|
@@ -135,7 +143,7 @@ require 'sneakers'
|
|
135
143
|
require 'redis'
|
136
144
|
require 'json'
|
137
145
|
require 'sneakers/metrics/logging_metrics'
|
138
|
-
Sneakers.configure
|
146
|
+
Sneakers.configure(metrics: Sneakers::Metrics::LoggingMetrics.new)
|
139
147
|
|
140
148
|
# ... rest of code
|
141
149
|
```
|
@@ -150,7 +158,6 @@ Now push a message again and you'll see:
|
|
150
158
|
|
151
159
|
Which increments `started` and `handled.ack`, and times the work unit.
|
152
160
|
|
153
|
-
|
154
161
|
From here, you can continue over to the
|
155
162
|
[Wiki](https://github.com/jondot/sneakers/wiki)
|
156
163
|
|
@@ -161,7 +168,7 @@ If you use Docker, there's some benefits to be had and you can use both
|
|
161
168
|
integration tests or a sample worker without setting up RabbitMQ or the
|
162
169
|
environment needed locally on your development box.
|
163
170
|
|
164
|
-
* To build a container run `docker build
|
171
|
+
* To build a container run `docker build . -t sneakers_sneakers`
|
165
172
|
* To run non-integration tests within a docker container, run `docker run --rm
|
166
173
|
sneakers_sneakers:latest`
|
167
174
|
* To run full integration tests within a docker topology including RabbitMQ,
|
@@ -176,23 +183,20 @@ environment needed locally on your development box.
|
|
176
183
|
It generates a more compact image, while the "regular" `Dockerfile` generates
|
177
184
|
a fatter image - yet faster to iterate when developing
|
178
185
|
|
179
|
-
|
180
186
|
# Compatibility
|
181
187
|
|
182
|
-
* Sneakers
|
183
|
-
* Sneakers 1.
|
188
|
+
* Sneakers 2.7.x and later (using Bunny 2.9) - Ruby 2.2.x
|
189
|
+
* Sneakers 1.1.x and later (using Bunny 2.x) - Ruby 2.x
|
190
|
+
* Sneakers 1.x.x and earlier - Ruby 1.9.x, 2.x
|
184
191
|
|
185
192
|
# Contributing
|
186
193
|
|
187
194
|
Fork, implement, add tests, pull request, get my everlasting thanks and a respectable place here :).
|
188
195
|
|
189
|
-
|
190
196
|
### Thanks:
|
191
197
|
|
192
198
|
To all Sneakers [Contributors](https://github.com/jondot/sneakers/graphs/contributors) - you make this happen, thanks!
|
193
199
|
|
194
|
-
|
195
|
-
|
196
200
|
# Copyright
|
197
201
|
|
198
|
-
Copyright (c) 2015 [Dotan Nahum](http://gplus.to/dotan) [@jondot](http://twitter.com/jondot). See [LICENSE](LICENSE.txt) for further details.
|
202
|
+
Copyright (c) 2015-2018 [Dotan Nahum](http://gplus.to/dotan) [@jondot](http://twitter.com/jondot). See [LICENSE](LICENSE.txt) for further details.
|
@@ -1,17 +1,20 @@
|
|
1
|
-
version: '
|
1
|
+
version: '3'
|
2
|
+
|
2
3
|
services:
|
3
4
|
sneakers:
|
4
5
|
build: .
|
5
6
|
depends_on:
|
6
7
|
- rabbitmq
|
7
8
|
- redis
|
9
|
+
|
8
10
|
rabbitmq:
|
9
|
-
image: rabbitmq:management
|
11
|
+
image: rabbitmq:management-alpine
|
10
12
|
ports:
|
11
13
|
- "5672:5672"
|
12
14
|
- "15672:15672"
|
15
|
+
|
13
16
|
redis:
|
14
|
-
image: redis
|
17
|
+
image: redis:alpine
|
15
18
|
ports:
|
16
19
|
- "6379:6379"
|
17
20
|
|
data/lib/sneakers/errors.rb
CHANGED
@@ -5,7 +5,7 @@ module Sneakers
|
|
5
5
|
module Handlers
|
6
6
|
#
|
7
7
|
# Maxretry uses dead letter policies on Rabbitmq to requeue and retry
|
8
|
-
# messages after failure (rejections
|
8
|
+
# messages after failure (rejections and errors). When the maximum
|
9
9
|
# number of retries is reached it will put the message on an error queue.
|
10
10
|
# This handler will only retry at the queue level. To accomplish that, the
|
11
11
|
# setup is a bit complex.
|
@@ -101,10 +101,6 @@ module Sneakers
|
|
101
101
|
handle_retry(hdr, props, msg, err)
|
102
102
|
end
|
103
103
|
|
104
|
-
def timeout(hdr, props, msg)
|
105
|
-
handle_retry(hdr, props, msg, :timeout)
|
106
|
-
end
|
107
|
-
|
108
104
|
def noop(hdr, props, msg)
|
109
105
|
|
110
106
|
end
|
data/lib/sneakers/queue.rb
CHANGED
@@ -38,7 +38,11 @@ class Sneakers::Queue
|
|
38
38
|
|
39
39
|
if exchange_name.length > 0
|
40
40
|
routing_keys.each do |key|
|
41
|
-
|
41
|
+
if @opts[:bind_arguments]
|
42
|
+
queue.bind(@exchange, routing_key: key, arguments: @opts[:bind_arguments])
|
43
|
+
else
|
44
|
+
queue.bind(@exchange, routing_key: key)
|
45
|
+
end
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
@@ -49,7 +53,7 @@ class Sneakers::Queue
|
|
49
53
|
handler_klass = worker.opts[:handler] || Sneakers::CONFIG.fetch(:handler)
|
50
54
|
handler = handler_klass.new(@channel, queue, worker.opts)
|
51
55
|
|
52
|
-
@consumer = queue.subscribe(:
|
56
|
+
@consumer = queue.subscribe(block: false, manual_ack: @opts[:ack]) do | delivery_info, metadata, msg |
|
53
57
|
worker.do_work(delivery_info, metadata, msg, handler)
|
54
58
|
end
|
55
59
|
nil
|
@@ -72,10 +76,10 @@ class Sneakers::Queue
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def create_bunny_connection
|
75
|
-
Bunny.new(@opts[:amqp], :
|
76
|
-
:
|
77
|
-
:
|
78
|
-
:
|
79
|
+
Bunny.new(@opts[:amqp], vhost: @opts[:vhost],
|
80
|
+
heartbeat: @opts[:heartbeat],
|
81
|
+
properties: @opts.fetch(:properties, {}),
|
82
|
+
logger: Sneakers::logger)
|
79
83
|
end
|
80
84
|
private :create_bunny_connection
|
81
85
|
end
|
data/lib/sneakers/version.rb
CHANGED
data/lib/sneakers/worker.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'sneakers/queue'
|
2
2
|
require 'sneakers/support/utils'
|
3
|
-
require 'timeout'
|
4
3
|
|
5
4
|
module Sneakers
|
6
5
|
module Worker
|
@@ -18,7 +17,6 @@ module Sneakers
|
|
18
17
|
opts = Sneakers::CONFIG.merge(opts)
|
19
18
|
|
20
19
|
@should_ack = opts[:ack]
|
21
|
-
@timeout_after = opts[:timeout_job_after]
|
22
20
|
@pool = pool || Concurrent::FixedThreadPool.new(opts[:threads] || Sneakers::Configuration::DEFAULTS[:threads])
|
23
21
|
@call_with_params = respond_to?(:work_with_params)
|
24
22
|
@content_type = opts[:content_type]
|
@@ -57,21 +55,15 @@ module Sneakers
|
|
57
55
|
|
58
56
|
begin
|
59
57
|
metrics.increment("work.#{self.class.name}.started")
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
res = work(deserialized_msg)
|
67
|
-
end
|
58
|
+
metrics.timing("work.#{self.class.name}.time") do
|
59
|
+
deserialized_msg = ContentType.deserialize(msg, @content_type || metadata && metadata[:content_type])
|
60
|
+
if @call_with_params
|
61
|
+
res = work_with_params(deserialized_msg, delivery_info, metadata)
|
62
|
+
else
|
63
|
+
res = work(deserialized_msg)
|
68
64
|
end
|
69
65
|
end
|
70
|
-
rescue
|
71
|
-
res = :timeout
|
72
|
-
worker_error(ex, log_msg: log_msg(msg), class: self.class.name,
|
73
|
-
message: msg, delivery_info: delivery_info, metadata: metadata)
|
74
|
-
rescue => ex
|
66
|
+
rescue StandardError, ScriptError => ex
|
75
67
|
res = :error
|
76
68
|
error = ex
|
77
69
|
worker_error(ex, log_msg: log_msg(msg), class: self.class.name,
|
@@ -83,8 +75,6 @@ module Sneakers
|
|
83
75
|
if res == :ack
|
84
76
|
# note to future-self. never acknowledge multiple (multiple=true) messages under threads.
|
85
77
|
handler.acknowledge(delivery_info, metadata, msg)
|
86
|
-
elsif res == :timeout
|
87
|
-
handler.timeout(delivery_info, metadata, msg)
|
88
78
|
elsif res == :error
|
89
79
|
handler.error(delivery_info, metadata, msg, error)
|
90
80
|
elsif res == :reject
|
data/log/.gitkeep
ADDED
File without changes
|
data/sneakers.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'sneakers/version'
|
@@ -18,22 +17,24 @@ Gem::Specification.new do |gem|
|
|
18
17
|
gem.executables = gem.files.grep(/^bin/).map { |f| File.basename(f) }
|
19
18
|
gem.test_files = gem.files.grep(/^(test|spec|features)\//)
|
20
19
|
gem.require_paths = ['lib']
|
20
|
+
|
21
21
|
gem.add_dependency 'serverengine', '~> 2.0.5'
|
22
|
-
gem.add_dependency 'bunny', '~> 2.
|
22
|
+
gem.add_dependency 'bunny', '~> 2.12'
|
23
23
|
gem.add_dependency 'concurrent-ruby', '~> 1.0'
|
24
24
|
gem.add_dependency 'thor'
|
25
|
+
gem.add_dependency 'rake'
|
25
26
|
|
26
27
|
# for integration environment (see .travis.yml and integration_spec)
|
27
28
|
gem.add_development_dependency 'rabbitmq_http_api_client'
|
28
29
|
gem.add_development_dependency 'redis'
|
29
30
|
|
31
|
+
gem.add_development_dependency 'rake'
|
32
|
+
gem.add_development_dependency 'minitest'
|
30
33
|
gem.add_development_dependency 'rr'
|
31
34
|
gem.add_development_dependency 'unparser', '0.2.2' # keep below 0.2.5 for ruby 2.0 compat.
|
32
|
-
gem.add_development_dependency 'guard-minitest'
|
33
35
|
gem.add_development_dependency 'metric_fu'
|
34
36
|
gem.add_development_dependency 'simplecov'
|
35
37
|
gem.add_development_dependency 'simplecov-rcov-text'
|
36
|
-
gem.add_development_dependency 'rake'
|
37
|
-
gem.add_development_dependency 'minitest'
|
38
38
|
gem.add_development_dependency 'guard'
|
39
|
+
gem.add_development_dependency 'guard-minitest'
|
39
40
|
end
|
data/spec/sneakers/queue_spec.rb
CHANGED
@@ -74,6 +74,17 @@ describe Sneakers::Queue do
|
|
74
74
|
q.subscribe(@mkworker)
|
75
75
|
end
|
76
76
|
|
77
|
+
it "supports setting arguments when binding" do
|
78
|
+
mock(@mkchan).queue("downloads", :durable => true) { @mkqueue }
|
79
|
+
q = Sneakers::Queue.new("downloads",
|
80
|
+
queue_vars.merge(:bind_arguments => { "os" => "linux", "cores" => 8 }))
|
81
|
+
|
82
|
+
mock(@mkqueue).bind(@mkex, :routing_key => "downloads", :arguments => { "os" => "linux", "cores" => 8 })
|
83
|
+
mock(@mkqueue).subscribe(:block => false, :manual_ack => true)
|
84
|
+
|
85
|
+
q.subscribe(@mkworker)
|
86
|
+
end
|
87
|
+
|
77
88
|
it "will use whatever handler the worker specifies" do
|
78
89
|
mock(@mkchan).queue("downloads", :durable => true) { @mkqueue }
|
79
90
|
@handler = Object.new
|
@@ -4,7 +4,7 @@ require 'sneakers'
|
|
4
4
|
require 'sneakers/runner'
|
5
5
|
|
6
6
|
describe Sneakers::Runner do
|
7
|
-
let(:logger) { Logger.new('logtest.log') }
|
7
|
+
let(:logger) { Logger.new('log/logtest.log') }
|
8
8
|
|
9
9
|
describe "with configuration that specifies a logger object" do
|
10
10
|
before do
|
@@ -27,7 +27,7 @@ describe Sneakers::Runner do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
describe Sneakers::RunnerConfig do
|
30
|
-
let(:logger) { Logger.new("logtest.log") }
|
30
|
+
let(:logger) { Logger.new("log/logtest.log") }
|
31
31
|
let(:runner_config) { Sneakers::Runner.new([]).instance_variable_get("@runnerconfig") }
|
32
32
|
|
33
33
|
describe "with a connection" do
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'sneakers'
|
3
|
-
require 'timeout'
|
4
3
|
require 'sneakers/handlers/oneshot'
|
5
4
|
require 'sneakers/handlers/maxretry'
|
6
5
|
require 'json'
|
@@ -77,13 +76,7 @@ describe 'Handlers' do
|
|
77
76
|
worker.do_work(@header, nil, :requeue, @handler)
|
78
77
|
end
|
79
78
|
|
80
|
-
it 'should work and handle user
|
81
|
-
mock(channel).reject(37, false)
|
82
|
-
|
83
|
-
worker.do_work(@header, nil, :timeout, @handler)
|
84
|
-
end
|
85
|
-
|
86
|
-
it 'should work and handle user-land error' do
|
79
|
+
it 'should work and handle user code error' do
|
87
80
|
mock(channel).reject(37, false)
|
88
81
|
|
89
82
|
worker.do_work(@header, nil, StandardError.new('boom!'), @handler)
|
@@ -198,7 +191,6 @@ describe 'Handlers' do
|
|
198
191
|
|
199
192
|
# it 'allows overriding the retry exchange name'
|
200
193
|
# it 'allows overriding the error exchange name'
|
201
|
-
# it 'allows overriding the retry timeout'
|
202
194
|
|
203
195
|
describe '#do_work' do
|
204
196
|
before do
|
@@ -289,36 +281,6 @@ describe 'Handlers' do
|
|
289
281
|
|
290
282
|
end
|
291
283
|
|
292
|
-
describe 'timeouts' do
|
293
|
-
describe 'more retries ahead' do
|
294
|
-
it 'should reject the message' do
|
295
|
-
mock(channel).reject(37, false)
|
296
|
-
|
297
|
-
worker.do_work(@header, @props_with_x_death, :timeout, @handler)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
describe 'no more retries left' do
|
302
|
-
let(:max_retries) { 1 }
|
303
|
-
|
304
|
-
it 'sends the rejection to the error queue' do
|
305
|
-
mock(@header).routing_key { '#' }
|
306
|
-
mock(channel).acknowledge(37, false)
|
307
|
-
@error_exchange.extend MockPublish
|
308
|
-
|
309
|
-
worker.do_work(@header, @props_with_x_death, :timeout, @handler)
|
310
|
-
@error_exchange.called.must_equal(true)
|
311
|
-
@error_exchange.opts.must_equal({ :routing_key => '#' })
|
312
|
-
data = JSON.parse(@error_exchange.data)
|
313
|
-
data['error'].must_equal('timeout')
|
314
|
-
data['num_attempts'].must_equal(2)
|
315
|
-
data['payload'].must_equal(Base64.encode64(:timeout.to_s))
|
316
|
-
data['properties'].must_equal(Base64.encode64(@props_with_x_death.to_json))
|
317
|
-
Time.parse(data['failed_at']).wont_be_nil
|
318
|
-
end
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
284
|
describe 'exceptions' do
|
323
285
|
describe 'more retries ahead' do
|
324
286
|
it 'should reject the message' do
|
@@ -360,33 +322,6 @@ describe 'Handlers' do
|
|
360
322
|
it 'should work and handle noops' do
|
361
323
|
worker.do_work(@header, @props, :wait, @handler)
|
362
324
|
end
|
363
|
-
|
364
|
-
# Since we encode in json, we want to make sure if the actual payload is
|
365
|
-
# json, then it's something you can get back out.
|
366
|
-
describe 'JSON payloads' do
|
367
|
-
let(:max_retries) { 1 }
|
368
|
-
|
369
|
-
it 'properly encodes the json payload' do
|
370
|
-
mock(@header).routing_key { '#' }
|
371
|
-
mock(channel).acknowledge(37, false)
|
372
|
-
@error_exchange.extend MockPublish
|
373
|
-
|
374
|
-
payload = {
|
375
|
-
data: 'hello',
|
376
|
-
response: :timeout
|
377
|
-
}
|
378
|
-
worker.do_work(@header, @props_with_x_death, payload.to_json, @handler)
|
379
|
-
@error_exchange.called.must_equal(true)
|
380
|
-
@error_exchange.opts.must_equal({ :routing_key => '#' })
|
381
|
-
data = JSON.parse(@error_exchange.data)
|
382
|
-
data['error'].must_equal('timeout')
|
383
|
-
data['num_attempts'].must_equal(2)
|
384
|
-
data['payload'].must_equal(Base64.encode64(payload.to_json))
|
385
|
-
data['properties'].must_equal(Base64.encode64(@props_with_x_death.to_json))
|
386
|
-
end
|
387
|
-
|
388
|
-
end
|
389
|
-
|
390
325
|
end
|
391
326
|
end
|
392
327
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'sneakers'
|
3
|
-
require 'timeout'
|
4
3
|
require 'serverengine'
|
5
4
|
|
6
5
|
class DummyWorker
|
@@ -21,7 +20,6 @@ class DummyWorker
|
|
21
20
|
:ack => false,
|
22
21
|
:threads => 50,
|
23
22
|
:prefetch => 40,
|
24
|
-
:timeout_job_after => 1,
|
25
23
|
:exchange => 'dummy',
|
26
24
|
:heartbeat => 5
|
27
25
|
|
@@ -37,16 +35,6 @@ class DefaultsWorker
|
|
37
35
|
end
|
38
36
|
end
|
39
37
|
|
40
|
-
class TimeoutWorker
|
41
|
-
include Sneakers::Worker
|
42
|
-
from_queue 'defaults',
|
43
|
-
:timeout_job_after => 0.5,
|
44
|
-
:ack => true
|
45
|
-
|
46
|
-
def work(msg)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
38
|
class AcksWorker
|
51
39
|
include Sneakers::Worker
|
52
40
|
from_queue 'defaults',
|
@@ -110,8 +98,7 @@ end
|
|
110
98
|
class MetricsWorker
|
111
99
|
include Sneakers::Worker
|
112
100
|
from_queue 'defaults',
|
113
|
-
:ack => true
|
114
|
-
:timeout_job_after => 0.5
|
101
|
+
:ack => true
|
115
102
|
|
116
103
|
def work(msg)
|
117
104
|
metrics.increment "foobar"
|
@@ -122,8 +109,7 @@ end
|
|
122
109
|
class WithParamsWorker
|
123
110
|
include Sneakers::Worker
|
124
111
|
from_queue 'defaults',
|
125
|
-
:ack => true
|
126
|
-
:timeout_job_after => 0.5
|
112
|
+
:ack => true
|
127
113
|
|
128
114
|
def work_with_params(msg, delivery_info, metadata)
|
129
115
|
msg
|
@@ -144,21 +130,6 @@ end
|
|
144
130
|
|
145
131
|
TestPool ||= Concurrent::ImmediateExecutor
|
146
132
|
|
147
|
-
def with_test_queuefactory(ctx, ack=true, msg=nil, nowork=false)
|
148
|
-
qf = Object.new
|
149
|
-
q = Object.new
|
150
|
-
s = Object.new
|
151
|
-
hdr = Object.new
|
152
|
-
mock(qf).build_queue(anything, anything, anything) { q }
|
153
|
-
mock(q).subscribe(anything){ s }
|
154
|
-
|
155
|
-
mock(s).each(anything) { |h,b| b.call(hdr, msg) unless nowork }
|
156
|
-
mock(hdr).ack{true} if !nowork && ack
|
157
|
-
mock(hdr).reject{true} if !nowork && !ack
|
158
|
-
|
159
|
-
mock(ctx).queue_factory { qf } # should return our own
|
160
|
-
end
|
161
|
-
|
162
133
|
describe Sneakers::Worker do
|
163
134
|
before do
|
164
135
|
@queue = Object.new
|
@@ -168,7 +139,7 @@ describe Sneakers::Worker do
|
|
168
139
|
stub(@queue).exchange { @exchange }
|
169
140
|
|
170
141
|
Sneakers.clear!
|
171
|
-
Sneakers.configure(:
|
142
|
+
Sneakers.configure(daemonize: true, log: 'sneakers.log')
|
172
143
|
Sneakers::Worker.configure_metrics
|
173
144
|
end
|
174
145
|
|
@@ -202,7 +173,6 @@ describe Sneakers::Worker do
|
|
202
173
|
:workers => 4,
|
203
174
|
:log => "sneakers.log",
|
204
175
|
:pid_path => "sneakers.pid",
|
205
|
-
:timeout_job_after => 5,
|
206
176
|
:prefetch => 10,
|
207
177
|
:threads => 10,
|
208
178
|
:share_threads => false,
|
@@ -241,7 +211,6 @@ describe Sneakers::Worker do
|
|
241
211
|
:workers => 4,
|
242
212
|
:log => "sneakers.log",
|
243
213
|
:pid_path => "sneakers.pid",
|
244
|
-
:timeout_job_after => 1,
|
245
214
|
:prefetch => 40,
|
246
215
|
:threads => 50,
|
247
216
|
:share_threads => false,
|
@@ -280,7 +249,6 @@ describe Sneakers::Worker do
|
|
280
249
|
:workers => 4,
|
281
250
|
:log => "sneakers.log",
|
282
251
|
:pid_path => "sneakers.pid",
|
283
|
-
:timeout_job_after => 5,
|
284
252
|
:prefetch => 10,
|
285
253
|
:threads => 10,
|
286
254
|
:share_threads => false,
|
@@ -404,26 +372,23 @@ describe Sneakers::Worker do
|
|
404
372
|
w.do_work(header, nil, "msg", handler)
|
405
373
|
end
|
406
374
|
|
407
|
-
it "should
|
375
|
+
it "should catch script exceptions from a bad work" do
|
376
|
+
w = AcksWorker.new(@queue, TestPool.new)
|
377
|
+
mock(w).work("msg").once{ raise ScriptError }
|
408
378
|
handler = Object.new
|
409
379
|
header = Object.new
|
410
|
-
w = AcksWorker.new(@queue, TestPool.new)
|
411
|
-
mock(w).work("msg").once{ raise "foo" }
|
412
|
-
mock(w.logger).error(/error="foo" error_class=RuntimeError worker_class=AcksWorker backtrace=/)
|
413
380
|
mock(handler).error(header, nil, "msg", anything)
|
381
|
+
mock(w.logger).error(/\[Exception error="ScriptError" error_class=ScriptError worker_class=AcksWorker backtrace=.*/)
|
414
382
|
w.do_work(header, nil, "msg", handler)
|
415
383
|
end
|
416
384
|
|
417
|
-
it "should
|
418
|
-
w = TimeoutWorker.new(@queue, TestPool.new)
|
419
|
-
stub(w).work("msg"){ sleep 10 }
|
420
|
-
|
385
|
+
it "should log exceptions from workers" do
|
421
386
|
handler = Object.new
|
422
387
|
header = Object.new
|
423
|
-
|
424
|
-
mock(
|
425
|
-
mock(w.logger).error(/error="
|
426
|
-
|
388
|
+
w = AcksWorker.new(@queue, TestPool.new)
|
389
|
+
mock(w).work("msg").once{ raise "foo" }
|
390
|
+
mock(w.logger).error(/error="foo" error_class=RuntimeError worker_class=AcksWorker backtrace=/)
|
391
|
+
mock(handler).error(header, nil, "msg", anything)
|
427
392
|
w.do_work(header, nil, "msg", handler)
|
428
393
|
end
|
429
394
|
|
@@ -456,14 +421,7 @@ describe Sneakers::Worker do
|
|
456
421
|
@worker.do_work(@delivery_info, nil, :requeue, handler)
|
457
422
|
end
|
458
423
|
|
459
|
-
it "should work and handle user
|
460
|
-
handler = Object.new
|
461
|
-
mock(handler).timeout(@delivery_info, nil, :timeout)
|
462
|
-
|
463
|
-
@worker.do_work(@delivery_info, nil, :timeout, handler)
|
464
|
-
end
|
465
|
-
|
466
|
-
it "should work and handle user-land error" do
|
424
|
+
it "should work and handle user code errors" do
|
467
425
|
handler = Object.new
|
468
426
|
mock(handler).error(@delivery_info, nil, :error, anything)
|
469
427
|
|
@@ -557,7 +515,6 @@ describe Sneakers::Worker do
|
|
557
515
|
# We don't care how these are called, we're focusing on metrics here.
|
558
516
|
stub(@handler).acknowledge
|
559
517
|
stub(@handler).reject
|
560
|
-
stub(@handler).timeout
|
561
518
|
stub(@handler).error
|
562
519
|
stub(@handler).noop
|
563
520
|
|
@@ -594,12 +551,6 @@ describe Sneakers::Worker do
|
|
594
551
|
@w.do_work(@delivery_info, nil, 'msg', @handler)
|
595
552
|
end
|
596
553
|
|
597
|
-
it 'should be able to meter timeouts' do
|
598
|
-
mock(@w.metrics).increment("work.MetricsWorker.handled.timeout").once
|
599
|
-
mock(@w).work('msg'){ sleep 10 }
|
600
|
-
@w.do_work(@delivery_info, nil, 'msg', @handler)
|
601
|
-
end
|
602
|
-
|
603
554
|
it 'defaults to noop when no response is specified' do
|
604
555
|
mock(@w.metrics).increment("foobar").once
|
605
556
|
mock(@w.metrics).increment("work.MetricsWorker.handled.noop").once
|
@@ -40,7 +40,7 @@ class StubbedWorker
|
|
40
40
|
end
|
41
41
|
|
42
42
|
describe Sneakers::WorkerGroup do
|
43
|
-
let(:logger) { Logger.new('logtest.log') }
|
43
|
+
let(:logger) { Logger.new('log/logtest.log') }
|
44
44
|
let(:connection) { Bunny.new(host: 'any-host.local') }
|
45
45
|
let(:runner) { Sneakers::Runner.new([DefaultsWorker]) }
|
46
46
|
let(:runner_config) { runner.instance_variable_get('@runnerconfig') }
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sneakers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dotan Nahum
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: serverengine
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: '2.12'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.
|
40
|
+
version: '2.12'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: concurrent-ruby
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,13 +67,13 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
|
-
type: :
|
76
|
+
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rabbitmq_http_api_client
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: redis
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
@@ -109,21 +109,21 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: rake
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0
|
117
|
+
version: '0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0
|
124
|
+
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: minitest
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
@@ -137,7 +137,7 @@ dependencies:
|
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: rr
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - ">="
|
@@ -151,7 +151,21 @@ dependencies:
|
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
154
|
+
name: unparser
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 0.2.2
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - '='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 0.2.2
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: metric_fu
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
156
170
|
requirements:
|
157
171
|
- - ">="
|
@@ -165,7 +179,7 @@ dependencies:
|
|
165
179
|
- !ruby/object:Gem::Version
|
166
180
|
version: '0'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
|
-
name: simplecov
|
182
|
+
name: simplecov
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
170
184
|
requirements:
|
171
185
|
- - ">="
|
@@ -179,7 +193,7 @@ dependencies:
|
|
179
193
|
- !ruby/object:Gem::Version
|
180
194
|
version: '0'
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
|
-
name:
|
196
|
+
name: simplecov-rcov-text
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
184
198
|
requirements:
|
185
199
|
- - ">="
|
@@ -193,7 +207,7 @@ dependencies:
|
|
193
207
|
- !ruby/object:Gem::Version
|
194
208
|
version: '0'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
|
-
name:
|
210
|
+
name: guard
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
198
212
|
requirements:
|
199
213
|
- - ">="
|
@@ -207,7 +221,7 @@ dependencies:
|
|
207
221
|
- !ruby/object:Gem::Version
|
208
222
|
version: '0'
|
209
223
|
- !ruby/object:Gem::Dependency
|
210
|
-
name: guard
|
224
|
+
name: guard-minitest
|
211
225
|
requirement: !ruby/object:Gem::Requirement
|
212
226
|
requirements:
|
213
227
|
- - ">="
|
@@ -239,7 +253,7 @@ files:
|
|
239
253
|
- README.md
|
240
254
|
- Rakefile
|
241
255
|
- bin/sneakers
|
242
|
-
- docker-compose.
|
256
|
+
- docker-compose.yml
|
243
257
|
- examples/benchmark_worker.rb
|
244
258
|
- examples/max_retry_handler.rb
|
245
259
|
- examples/metrics_worker.rb
|
@@ -272,6 +286,7 @@ files:
|
|
272
286
|
- lib/sneakers/version.rb
|
273
287
|
- lib/sneakers/worker.rb
|
274
288
|
- lib/sneakers/workergroup.rb
|
289
|
+
- log/.gitkeep
|
275
290
|
- scripts/local_integration
|
276
291
|
- scripts/local_worker
|
277
292
|
- sneakers.gemspec
|
@@ -312,7 +327,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
312
327
|
version: '0'
|
313
328
|
requirements: []
|
314
329
|
rubyforge_project:
|
315
|
-
rubygems_version: 2.6.
|
330
|
+
rubygems_version: 2.6.8
|
316
331
|
signing_key:
|
317
332
|
specification_version: 4
|
318
333
|
summary: Fast background processing framework for Ruby and RabbitMQ
|