shoryuken-waiter 0.0.1 → 0.0.2
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 +4 -4
- data/.gitignore +1 -0
- data/README.md +61 -7
- data/lib/shoryuken/waiter.rb +7 -5
- data/lib/shoryuken/waiter/version.rb +1 -1
- data/shoryuken-waiter.gemspec +5 -5
- metadata +20 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47dca392390acc823bec52e81a7e30dc0ea1efc2
|
4
|
+
data.tar.gz: 6ad3144086dff7404d74e0a0742ca4b6c4537723
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 888f44672933d04b697606832924612d37c9377230a8544929138164b4f0983e5f07b5c3f1fc82508fcab1ed1d2a7962b243bf42d907d746f1a39661a2f59cc2
|
7
|
+
data.tar.gz: 0f6221228bba8f6cdc9af999bc9e5f93b97f054a5e9c4ef32ba592aac92f50406bc1a906aade0d7ad95908bb2fb6dc8c2a85dbd5b6c6aabcb4a7a3fed546f1ae
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -4,18 +4,72 @@
|
|
4
4
|
[](https://gemnasium.com/farski/shoryuken-waiter)
|
5
5
|
[](https://travis-ci.org/farski/shoryuken-waiter)
|
6
6
|
[](https://codeclimate.com/github/farski/shoryuken-waiter)
|
7
|
-
[](https://coveralls.io/
|
7
|
+
[](https://coveralls.io/github/farski/shoryuken-waiter?branch=master)
|
8
8
|
|
9
|
-
Based heavily on [`shoryuken-later`](https://github.com/joekhoobyar/shoryuken-later).
|
9
|
+
Based heavily on the concept of [`shoryuken-later`](https://github.com/joekhoobyar/shoryuken-later), `Shoryuken::Waiter` allows jobs to be scheduled greater that 15 minutes into the future when using [Shoryuken](https://github.com/phstc/shoryuken).
|
10
10
|
|
11
|
-
Version 0.x is tightly coupled Rails and Shoryuken SQS queues. 1.x should add support for Shoryuken workers (currently only Active Job is supported), and more configurable DynamoDB tables.
|
11
|
+
_**Notice:** Version 0.x is tightly coupled Rails and Shoryuken SQS queues. 1.x should add support for Shoryuken workers (currently only Active Job is supported), and more configurable DynamoDB tables._
|
12
12
|
|
13
|
-
|
13
|
+
## Usage
|
14
14
|
|
15
|
-
|
15
|
+
### Integration with ActiveJob
|
16
|
+
|
17
|
+
Because **[SQS](https://aws.amazon.com/sqs/)** only allows messages to be [delayed up to 15 minutes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html), the [`Active Job`](http://guides.rubyonrails.org/active_job_basics.html) adapter that ships with `Shoryuken` does not allow jobs to be scheduled further than 15 minutes out. `Shoryuken::Waiter` provides a replacement adapter that wraps the `Shoryuken` adapter, and allows for jobs to be scheduled arbitrarily far into the future.
|
18
|
+
```
|
19
|
+
# config/application.rb
|
20
|
+
config.active_job.queue_adapter = :shoryuken_waiter
|
21
|
+
```
|
22
|
+
|
23
|
+
If a job is created with a delay of more than 15 minutes, **and** `Shoryuken::Waiter` finds a **[DynamoDB](https://aws.amazon.com/dynamodb/)** table whose name matches the name of the queue for which the job was intended, the properties of the job are captured to that table, allowing it to be rescheduled later on. If a matching table can't be found **or** the job's is 15 minutes or less the native `Shoryuken` adapters handles it.
|
24
|
+
|
25
|
+
### The schedule poller
|
26
|
+
|
27
|
+
There is no separate poller process that is run to watch for scheduled jobs. Whenever the `Shoryuken` message processor starts up, a Celluloid supervisor maintains a single `Shoryuken::Waiter::Querier` that polls **DynamoDB** for jobs. The poller shuts down when `Shoryuken` stops.
|
28
|
+
|
29
|
+
The frequency that tables are queried for scheduleable jobs is `5.minutes` by default. It can be customized by setting the `delay` property in the `Shoryuken` configuration.
|
30
|
+
|
31
|
+
```
|
32
|
+
# config/shoryuken.yml
|
33
|
+
waiter:
|
34
|
+
delay: 30 # seconds
|
35
|
+
```
|
36
|
+
|
37
|
+
### Queues & Tables
|
38
|
+
|
39
|
+
When `Shoryuken::Waiter` loads it tries to find a **DynamoDB** table for each **SQS** `Shoryuken` queue that is configured. When a table with a matching name can't be found, `Shoryuken::Waiter` will not poll for jobs intended for that queue, and creating jobs intended for that queue is handled by the the `Shoryuken` `Active Job` adapter.
|
40
|
+
|
41
|
+
_**Note:** There is no technical reason that each queue needs it's own table. It would be more cost effective to put all jobs into a single table, so that may be a change that is made in the future._
|
42
|
+
|
43
|
+
#### Creating DynamoDB Tables
|
44
|
+
|
45
|
+
Tables being used with `Shoryuken::Waiter` must be created with certain properties to work correctly.
|
46
|
+
|
47
|
+
* **Table name**: The name of the table must match the name of an **SQS** queue registered with `Shoryuken`
|
48
|
+
* **Primary key**: The `item key` must be a `String` with the value `scheduler`, and the `sort key` must be a `String` with the value `job_id`
|
49
|
+
* **Secondary index**: An index (generally a *Local Secondary Index*) must be added to the table. The `item key` of the index's **primary key** must be a `String` with the value `scheduler`, and the `sort key` of the **primary key** must be a `Number` with the value `perform_at`. The **index name** must be `scheduler-perform_at-index`. **Projected attributes** generally can be set to `all`.
|
50
|
+
|
51
|
+
Other properties of the table, such as the **provisioned capacity** will be application dependent.
|
52
|
+
|
53
|
+
## Internals
|
54
|
+
|
55
|
+
When a job is scheduled normally with `Shoryuken`, the message is sent to **SQS** with four properties `queue_url`, `message_body`, `delay_seconds`, and `message_attributes`.
|
56
|
+
|
57
|
+
When the job must be delayed, `Shoryuken::Waiter` captures enough information to recreate an identical **SQS** message later on. The `message_body` and `message_attributes` are stored unaltered. `delay_seconds` is tranformed into a timestamp, relative to when the job was created, which can be used to query items from a **DynamoDB** table. The message's `queue_url` is discarded, since it can be recreated from the job's queue name, which is already captured as part of the `message_body`.
|
16
58
|
|
17
59
|
### Query
|
18
60
|
|
19
|
-
|
61
|
+
After a job is delayed and stored in a **DynamoDB** table, it must be retrieved at the appropriate time, and sent to **SQS** like was originally intended.
|
62
|
+
|
63
|
+
The poller needs a way of efficiently finding jobs in tables, and the **DynamoDB** API provides the `query` operation for that purpose.
|
64
|
+
|
65
|
+
The `query` operation can either search based on just a **hash key**, or a **hash key** and a **range key**. `Shoryuken::Waiter` is looking for all jobs that are scheduled before a certain point in time (15 minutes from the time of the query). It's only possible to make comparison queries with a **range key**, so using just a hash key would not work. Since the hash key is required for all query operations, but there is no meaningful key in this case, it's value can be arbitrary, as long as it is consistent.
|
66
|
+
|
67
|
+
Using the job's timestamp as the **range key** would be reasonable, except that more than one job may be scheduled for the same time. Since all items are being given the same **hash key**, identical **range keys** would violate the primary key uniqueness constraint. Instead of using a value from the table's primary key for the comparison query, a **secondary index** can be added to the table, which also allows for **range keys** to be queried.
|
68
|
+
|
69
|
+
The **range key** of the table's primary key simply needs to provide uniqueness, so the job's unique ID can be used for that. The **hash key** of the secondary index must match the hash key of the table, so it will also be the arbitrary value that is selected. The **range key** will be the `perform_at` timestamp, and since secondary indexes do not require primary keys to be unique, there is no risk of collision between jobs with the same timestamp.
|
70
|
+
|
71
|
+
A query can now be performed to find any item in the table with a given **hash key** (the arbitrary value shared by all items in the table) and a **range key** that only returns jobs scheduled no later than 15 minutes from now.
|
72
|
+
|
73
|
+
If the query returns any items, they must be turned back into **SQS** messages and sent to their intended queue. The stored values are pulled back out of the item, and transformed if necessary (e.g. turning `perform_at` back to `delay_seconds`).
|
20
74
|
|
21
|
-
|
75
|
+
The query returns sets of items, and **SQS** can be sent sets of messages (at most 10). The batches of items are processed into batches of messages, which get sent back to `Shoryuken`, and ultimately to **SQS**.
|
data/lib/shoryuken/waiter.rb
CHANGED
@@ -44,9 +44,11 @@ end
|
|
44
44
|
|
45
45
|
require "shoryuken/waiter/extensions/active_job_adapter" if defined? ::ActiveJob
|
46
46
|
|
47
|
-
Shoryuken.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
Shoryuken.configure_server do |config|
|
48
|
+
config.on(:startup) do
|
49
|
+
tables = Shoryuken::Waiter.tables
|
50
|
+
queues = Shoryuken.queues.uniq
|
51
|
+
Shoryuken.logger.info { "[Shoryuken::Waiter] Starting. Polling #{tables.count} tables for #{queues.count} queues" }
|
52
|
+
Shoryuken::Waiter::Querier.supervise_as :shoryuken_waiter_querier
|
53
|
+
end
|
52
54
|
end
|
data/shoryuken-waiter.gemspec
CHANGED
@@ -21,12 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.10"
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
-
spec.add_development_dependency "minitest"
|
24
|
+
spec.add_development_dependency "minitest", "~> 5.8"
|
25
25
|
spec.add_development_dependency "coveralls", "~> 0"
|
26
|
-
spec.add_development_dependency "pry"
|
27
|
-
spec.add_development_dependency "dotenv"
|
28
|
-
spec.add_development_dependency "rubocop"
|
26
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
27
|
+
spec.add_development_dependency "dotenv", "~> 2.0"
|
28
|
+
spec.add_development_dependency "rubocop", "~> 0.34"
|
29
29
|
|
30
|
-
spec.add_dependency "shoryuken", "~> 2
|
30
|
+
spec.add_dependency "shoryuken", "~> 2"
|
31
31
|
spec.add_dependency "aws-sdk", "~> 2"
|
32
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shoryuken-waiter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Kalafarski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: minitest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '5.8'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '5.8'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: coveralls
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,58 +70,58 @@ dependencies:
|
|
70
70
|
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
75
|
+
version: '0.10'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
82
|
+
version: '0.10'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: dotenv
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
89
|
+
version: '2.0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
96
|
+
version: '2.0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rubocop
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
103
|
+
version: '0.34'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
110
|
+
version: '0.34'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: shoryuken
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 2
|
117
|
+
version: '2'
|
118
118
|
type: :runtime
|
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: 2
|
124
|
+
version: '2'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: aws-sdk
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|