cloudwatch_scheduler 0.1.2 → 1.1.1
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 +5 -5
- data/.github/workflows/ci.yml +49 -0
- data/.gitignore +7 -5
- data/.rubocop.yml +328 -66
- data/.travis.yml +5 -3
- data/Appraisals +7 -4
- data/Gemfile +5 -2
- data/Guardfile +2 -0
- data/README.md +43 -2
- data/Rakefile +3 -1
- data/cloudwatch_scheduler.gemspec +16 -11
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/{rails_5.0.gemfile → rails_5.2.gemfile} +5 -3
- data/gemfiles/{rails_4.2.gemfile → rails_6.0.gemfile} +5 -3
- data/lib/cloudwatch_scheduler.rb +1 -3
- data/lib/cloudwatch_scheduler/configuration.rb +5 -4
- data/lib/cloudwatch_scheduler/engine.rb +4 -0
- data/lib/cloudwatch_scheduler/job.rb +2 -1
- data/lib/cloudwatch_scheduler/provisioner.rb +42 -38
- data/lib/cloudwatch_scheduler/task.rb +11 -9
- data/lib/cloudwatch_scheduler/tasks/setup.rake +2 -4
- data/lib/cloudwatch_scheduler/version.rb +3 -1
- metadata +51 -24
- data/gemfiles/rails_4.2.gemfile.lock +0 -209
- data/gemfiles/rails_5.0.gemfile.lock +0 -213
data/.travis.yml
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- 2.3
|
5
|
-
|
4
|
+
- 2.5.3
|
5
|
+
- 2.6.1
|
6
|
+
before_install: gem install bundler
|
6
7
|
gemfile:
|
7
|
-
- gemfiles/rails_4.2.gemfile
|
8
8
|
- gemfiles/rails_5.0.gemfile
|
9
|
+
- gemfiles/rails_5.1.gemfile
|
10
|
+
- gemfiles/rails_5.2.gemfile
|
data/Appraisals
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
|
-
appraise "rails-
|
3
|
-
gem "
|
3
|
+
appraise "rails-5.2" do
|
4
|
+
gem "railties", "~> 5.2.0"
|
5
|
+
gem "activejob", "~> 5.2.0"
|
4
6
|
end
|
5
7
|
|
6
|
-
appraise "rails-
|
7
|
-
gem "
|
8
|
+
appraise "rails-6.1" do
|
9
|
+
gem "railties", "~> 6.1"
|
10
|
+
gem "activejob", "~> 6.1"
|
8
11
|
end
|
data/Gemfile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
2
4
|
|
3
5
|
# Specify your gem's dependencies in cloudwatch_scheduler.gemspec
|
4
6
|
gemspec
|
@@ -8,5 +10,6 @@ group :development, :test do
|
|
8
10
|
gem "guard"
|
9
11
|
gem "guard-rspec"
|
10
12
|
|
11
|
-
gem "
|
13
|
+
gem "rubocop"
|
14
|
+
gem "rubocop-rspec"
|
12
15
|
end
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# CloudwatchScheduler
|
2
2
|
|
3
|
+
[](https://github.com/paul/cloudwatch_scheduler/actions)
|
4
|
+
|
3
5
|
Are you using Rails 4.2+ and ActiveJob with the [Shoryuken
|
4
6
|
driver][shoryuken-driver] to use SQS? Do you have recurring jobs that you kick
|
5
7
|
off periodically with the [amazing Clockwork gem][clockwork]? Tired of paying
|
@@ -32,7 +34,7 @@ Or install it yourself as:
|
|
32
34
|
|
33
35
|
## Usage
|
34
36
|
|
35
|
-
Make yourself a `config/
|
37
|
+
Make yourself a `config/cloudwatch_schedule.rb` file:
|
36
38
|
|
37
39
|
```ruby
|
38
40
|
require "cloudwatch_scheduler"
|
@@ -52,10 +54,49 @@ CloudwatchScheduler do |config|
|
|
52
54
|
end
|
53
55
|
```
|
54
56
|
|
57
|
+
You'll also need to inform Shoryuken about the `cloudwatch_scheduler` queue,
|
58
|
+
either in the `config/shoryuken.yml` or with `-q cloudwatch_scheduler` on the
|
59
|
+
command line.
|
60
|
+
|
55
61
|
Then do `rake cloudwatch_scheduler:setup`, and CloudwatchScheduler will provision the events and
|
56
62
|
cloudwatch_scheduler queue. Then, start your Shoruken workers as normal, and the
|
57
63
|
`CloudwatchScheduler::Job` will get those events, and perform the tasks defined.
|
58
64
|
|
65
|
+
### IAM Permissions
|
66
|
+
|
67
|
+
The setup task requires some permissions in the AWS account to create the queue
|
68
|
+
and Cloudwatch Events. Here's a sample policy:
|
69
|
+
|
70
|
+
```json
|
71
|
+
{
|
72
|
+
"Version": "2012-10-17",
|
73
|
+
"Statement": [
|
74
|
+
{
|
75
|
+
"Effect": "Allow",
|
76
|
+
"Action": [
|
77
|
+
"sqs:CreateQueue",
|
78
|
+
"sqs:GetQueueAttributes",
|
79
|
+
"sqs:SetQueueAttributes",
|
80
|
+
],
|
81
|
+
"Resource": [
|
82
|
+
"arn:aws:sqs:REGION:AWS_ACCOUNT:cloudwatch_scheduler",
|
83
|
+
"arn:aws:sqs:REGION:AWS_ACCOUNT:cloudwatch_scheduler-failures"
|
84
|
+
]
|
85
|
+
},
|
86
|
+
{
|
87
|
+
"Effect": "Allow",
|
88
|
+
"Action": [
|
89
|
+
"events:PutRule",
|
90
|
+
"events:PutTargets"
|
91
|
+
],
|
92
|
+
"Resource": [
|
93
|
+
"*"
|
94
|
+
]
|
95
|
+
}
|
96
|
+
]
|
97
|
+
}
|
98
|
+
```
|
99
|
+
|
59
100
|
## Development
|
60
101
|
|
61
102
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
@@ -74,6 +115,6 @@ Bug reports and pull requests are welcome on GitHub at
|
|
74
115
|
https://github.com/paul/cloudwatch_scheduler.
|
75
116
|
|
76
117
|
[shoryuken-driver]: https://github.com/phstc/shoryuken/wiki/Rails-Integration-Active-Job
|
77
|
-
[clockwork]: https://
|
118
|
+
[clockwork]: https://rubygems.org/gems/clockwork
|
78
119
|
[cloudwatch-events]: http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/ScheduledEvents.html
|
79
120
|
|
data/Rakefile
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
5
|
+
require "cloudwatch_scheduler/version"
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
8
|
spec.name = "cloudwatch_scheduler"
|
@@ -9,20 +10,24 @@ Gem::Specification.new do |spec|
|
|
9
10
|
spec.authors = ["Paul Sadauskas"]
|
10
11
|
spec.email = ["psadauskas@gmail.com"]
|
11
12
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
13
|
+
spec.summary = "Use AWS CloudWatch events to trigger recurring jobs."
|
14
|
+
spec.description = "Use Cloudwatch Events to kick off recurring SQS ActiveJob jobs."
|
14
15
|
spec.homepage = "https://github.com/paul/cloudwatch_scheduler"
|
15
16
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
18
|
spec.bindir = "exe"
|
18
|
-
spec.executables = spec.files.grep(%r
|
19
|
+
spec.executables = spec.files.grep(%r(^exe/)) { |f| File.basename(f) }
|
19
20
|
spec.require_paths = ["lib"]
|
20
21
|
|
21
|
-
spec.
|
22
|
-
|
23
|
-
spec.add_dependency "
|
22
|
+
spec.required_ruby_version = "~> 2.5"
|
23
|
+
|
24
|
+
spec.add_dependency "aws-sdk-cloudwatchevents", "~> 1.13"
|
25
|
+
spec.add_dependency "aws-sdk-sqs", "~> 1.10"
|
26
|
+
spec.add_dependency "rails", ">= 5.2.0"
|
27
|
+
spec.add_dependency "shoryuken", ">= 2.0"
|
24
28
|
|
25
|
-
spec.add_development_dependency "
|
26
|
-
spec.add_development_dependency "
|
29
|
+
spec.add_development_dependency "appraisal", "~> 2.2.0"
|
30
|
+
spec.add_development_dependency "bundler", ">= 1.12"
|
31
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
27
32
|
spec.add_development_dependency "rspec", "~> 3.0"
|
28
33
|
end
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file was generated by Appraisal
|
2
4
|
|
3
5
|
source "https://rubygems.org"
|
4
6
|
|
5
|
-
gem "
|
7
|
+
gem "activejob", "~> 5.2.0"
|
8
|
+
gem "railties", "~> 5.2.0"
|
6
9
|
|
7
10
|
group :development, :test do
|
8
11
|
gem "awesome_print"
|
9
12
|
gem "guard"
|
10
13
|
gem "guard-rspec"
|
11
|
-
gem "appraisal"
|
12
14
|
end
|
13
15
|
|
14
|
-
gemspec :
|
16
|
+
gemspec path: "../"
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# This file was generated by Appraisal
|
2
4
|
|
3
5
|
source "https://rubygems.org"
|
4
6
|
|
5
|
-
gem "
|
7
|
+
gem "activejob", "~> 6.0"
|
8
|
+
gem "railties", "~> 6.0"
|
6
9
|
|
7
10
|
group :development, :test do
|
8
11
|
gem "awesome_print"
|
9
12
|
gem "guard"
|
10
13
|
gem "guard-rspec"
|
11
|
-
gem "appraisal"
|
12
14
|
end
|
13
15
|
|
14
|
-
gemspec :
|
16
|
+
gemspec path: "../"
|
data/lib/cloudwatch_scheduler.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
require "cloudwatch_scheduler/configuration"
|
3
4
|
require "cloudwatch_scheduler/task"
|
@@ -10,10 +11,7 @@ def CloudwatchScheduler(&config)
|
|
10
11
|
end
|
11
12
|
|
12
13
|
module CloudwatchScheduler
|
13
|
-
|
14
14
|
def self.global
|
15
15
|
@global ||= CloudwatchScheduler::Configuration.new
|
16
16
|
end
|
17
|
-
|
18
17
|
end
|
19
|
-
|
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/numeric/time"
|
2
4
|
|
3
5
|
module CloudwatchScheduler
|
4
6
|
class Configuration
|
5
|
-
|
6
|
-
attr_accessor :queue_name,
|
7
|
-
:queue_visibility_timeout,
|
7
|
+
attr_accessor :queue_visibility_timeout,
|
8
8
|
:queue_max_receive_count,
|
9
9
|
:use_dead_letter_queue
|
10
10
|
|
@@ -30,9 +30,10 @@ module CloudwatchScheduler
|
|
30
30
|
@use_dead_letter_queue = true
|
31
31
|
end
|
32
32
|
|
33
|
+
attr_writer :queue_name
|
34
|
+
|
33
35
|
def queue_name
|
34
36
|
@queue_name ||= CloudwatchScheduler::Job.queue_name
|
35
37
|
end
|
36
|
-
|
37
38
|
end
|
38
39
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module CloudwatchScheduler
|
3
4
|
class Engine < Rails::Engine
|
@@ -13,6 +14,9 @@ module CloudwatchScheduler
|
|
13
14
|
CloudwatchScheduler::Job.queue_name,
|
14
15
|
ActiveJob::QueueAdapters::ShoryukenAdapter::JobWrapper
|
15
16
|
)
|
17
|
+
|
18
|
+
# Load the configuration
|
19
|
+
require Rails.root.join("config/cloudwatch_schedule").to_s
|
16
20
|
end
|
17
21
|
|
18
22
|
rake_tasks do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CloudwatchScheduler
|
2
4
|
class Job < ::ApplicationJob
|
3
5
|
queue_as :cloudwatch_scheduler
|
@@ -9,6 +11,5 @@ module CloudwatchScheduler
|
|
9
11
|
def perform(job_to_spawn)
|
10
12
|
@config.tasks[job_to_spawn].invoke
|
11
13
|
end
|
12
|
-
|
13
14
|
end
|
14
15
|
end
|
@@ -1,14 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "aws-sdk-sqs"
|
4
|
+
require "aws-sdk-cloudwatchevents"
|
2
5
|
|
3
6
|
module CloudwatchScheduler
|
4
7
|
class Provisioner
|
5
|
-
|
6
8
|
attr_reader :config
|
7
9
|
|
8
10
|
def initialize(config, sqs_client: Aws::SQS::Client.new,
|
9
|
-
|
11
|
+
cwe_client: Aws::CloudWatchEvents::Client.new)
|
10
12
|
@config = config
|
11
|
-
@sqs_client
|
13
|
+
@sqs_client = sqs_client
|
14
|
+
@cwe_client = cwe_client
|
12
15
|
end
|
13
16
|
|
14
17
|
def provision
|
@@ -20,37 +23,24 @@ module CloudwatchScheduler
|
|
20
23
|
attributes = { "VisibilityTimeout" => config.queue_visibility_timeout.to_s }
|
21
24
|
@queue_url = sqs.create_queue(queue_name: queue_name, attributes: attributes).queue_url
|
22
25
|
|
23
|
-
if config.use_dead_letter_queue
|
24
|
-
dlq_name = queue_name + "-failures"
|
25
|
-
dlq_url = sqs.create_queue(queue_name: dlq_name).queue_url
|
26
|
-
dlq_arn = sqs.get_queue_attributes(queue_url: dlq_url, attribute_names: ["QueueArn"]).attributes["QueueArn"]
|
27
|
-
|
28
|
-
redrive_attrs = {
|
29
|
-
maxReceiveCount: config.queue_max_receive_count.to_s,
|
30
|
-
deadLetterTargetArn: dlq_arn
|
31
|
-
}.to_json
|
32
|
-
|
33
|
-
attributes = {"RedrivePolicy" => redrive_attrs}
|
34
|
-
|
35
|
-
sqs.set_queue_attributes(queue_url: queue_url, attributes: attributes)
|
36
|
-
end
|
26
|
+
create_dead_letter_queue! if config.use_dead_letter_queue
|
37
27
|
end
|
38
28
|
|
39
29
|
def create_events!
|
40
30
|
rule_arns = config.tasks.map do |_name, task|
|
41
31
|
rule_arn = cwe.put_rule(
|
42
|
-
name:
|
32
|
+
name: task.rule_name,
|
43
33
|
schedule_expression: task.rule_schedule_expression,
|
44
|
-
state:
|
45
|
-
description:
|
34
|
+
state: "ENABLED",
|
35
|
+
description: "CloudwatchScheduler task defined at #{task.code.source_location}"
|
46
36
|
).rule_arn
|
47
37
|
|
48
38
|
cwe.put_targets(
|
49
|
-
rule:
|
39
|
+
rule: task.rule_name,
|
50
40
|
targets: [
|
51
41
|
{
|
52
|
-
id:
|
53
|
-
arn:
|
42
|
+
id: task.rule_name,
|
43
|
+
arn: queue_arn,
|
54
44
|
input: task.event_data.to_json
|
55
45
|
}
|
56
46
|
]
|
@@ -60,28 +50,28 @@ module CloudwatchScheduler
|
|
60
50
|
end
|
61
51
|
|
62
52
|
policy = {
|
63
|
-
|
64
|
-
|
65
|
-
|
53
|
+
Version: "2012-10-17",
|
54
|
+
Id: "#{queue_arn}/SQSDefaultPolicy",
|
55
|
+
Statement: rule_arns.map do |rule_arn|
|
66
56
|
{
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
57
|
+
Sid: "TrustCWESendingToSQS",
|
58
|
+
Effect: "Allow",
|
59
|
+
Principal: {
|
60
|
+
AWS: "*"
|
71
61
|
},
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
62
|
+
Action: "sqs:SendMessage",
|
63
|
+
Resource: queue_arn,
|
64
|
+
Condition: {
|
65
|
+
ArnEquals: {
|
76
66
|
"aws:SourceArn": rule_arn
|
77
67
|
}
|
78
68
|
}
|
79
69
|
}
|
80
|
-
|
70
|
+
end
|
81
71
|
}
|
82
72
|
|
83
73
|
sqs.set_queue_attributes(
|
84
|
-
queue_url:
|
74
|
+
queue_url: queue_url,
|
85
75
|
attributes: {
|
86
76
|
"Policy" => policy.to_json
|
87
77
|
}
|
@@ -90,6 +80,21 @@ module CloudwatchScheduler
|
|
90
80
|
|
91
81
|
private
|
92
82
|
|
83
|
+
def create_dead_letter_queue!
|
84
|
+
dlq_name = queue_name + "-failures"
|
85
|
+
dlq_url = sqs.create_queue(queue_name: dlq_name).queue_url
|
86
|
+
dlq_arn = sqs.get_queue_attributes(queue_url: dlq_url, attribute_names: ["QueueArn"]).attributes["QueueArn"]
|
87
|
+
|
88
|
+
redrive_attrs = {
|
89
|
+
maxReceiveCount: config.queue_max_receive_count.to_s,
|
90
|
+
deadLetterTargetArn: dlq_arn
|
91
|
+
}.to_json
|
92
|
+
|
93
|
+
attributes = { "RedrivePolicy" => redrive_attrs }
|
94
|
+
|
95
|
+
sqs.set_queue_attributes(queue_url: queue_url, attributes: attributes)
|
96
|
+
end
|
97
|
+
|
93
98
|
def queue_name
|
94
99
|
config.queue_name
|
95
100
|
end
|
@@ -112,6 +117,5 @@ module CloudwatchScheduler
|
|
112
117
|
def sqs
|
113
118
|
@sqs_client
|
114
119
|
end
|
115
|
-
|
116
120
|
end
|
117
121
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/digest/uuid"
|
2
4
|
|
3
5
|
module CloudwatchScheduler
|
4
6
|
class Task
|
@@ -8,6 +10,7 @@ module CloudwatchScheduler
|
|
8
10
|
@name = name
|
9
11
|
@every, @cron = every, cron
|
10
12
|
fail "You must specify one of every: or cron:" unless [@every, @cron].any?
|
13
|
+
|
11
14
|
@code = code
|
12
15
|
end
|
13
16
|
|
@@ -24,18 +27,18 @@ module CloudwatchScheduler
|
|
24
27
|
# "locale":"en"}
|
25
28
|
def event_data
|
26
29
|
{
|
27
|
-
job_class:
|
28
|
-
job_id:
|
30
|
+
job_class: CloudwatchScheduler::Job.name,
|
31
|
+
job_id: job_id,
|
29
32
|
queue_name: CloudwatchScheduler::Job.queue_name,
|
30
|
-
arguments:
|
31
|
-
locale:
|
32
|
-
priority:
|
33
|
+
arguments: [name],
|
34
|
+
locale: "en",
|
35
|
+
priority: nil
|
33
36
|
}
|
34
37
|
end
|
35
38
|
|
36
39
|
def rule_name
|
37
|
-
limit = 64 - CloudwatchScheduler::Job.queue_name
|
38
|
-
[name[0, limit-1], CloudwatchScheduler::Job.queue_name].join("-")
|
40
|
+
limit = 64 - CloudwatchScheduler::Job.queue_name.length
|
41
|
+
[name[0, limit - 1], CloudwatchScheduler::Job.queue_name].join("-")
|
39
42
|
end
|
40
43
|
|
41
44
|
def rule_schedule_expression
|
@@ -65,6 +68,5 @@ module CloudwatchScheduler
|
|
65
68
|
def cron_exp
|
66
69
|
"cron(#{@cron})"
|
67
70
|
end
|
68
|
-
|
69
71
|
end
|
70
72
|
end
|