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.
data/.travis.yml CHANGED
@@ -1,8 +1,10 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3.1
5
- before_install: gem install bundler -v 1.12.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-4.2" do
3
- gem "rails", "~> 4.2.0"
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-5.0" do
7
- gem "rails", "~> 5.0.0"
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
- source 'https://rubygems.org'
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 "appraisal"
13
+ gem "rubocop"
14
+ gem "rubocop-rspec"
12
15
  end
data/Guardfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # A sample Guardfile
2
4
  # More info at https://github.com/guard/guard#readme
3
5
 
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # CloudwatchScheduler
2
2
 
3
+ [![Actions Status](https://github.com/paul/cloudwatch_scheduler/workflows/CI/badge.svg)](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/cloudwatch_scheduler.rb` file:
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://github.com/tomykaira/clockwork
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,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
@@ -1,7 +1,8 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
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 'cloudwatch_scheduler/version'
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 = %q{Use AWS CloudWatch events to trigger recurring jobs.}
13
- spec.description = %q{Use Cloudwatch Events to kick off recurring SQS ActiveJob jobs.}
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{^exe/}) { |f| File.basename(f) }
19
+ spec.executables = spec.files.grep(%r(^exe/)) { |f| File.basename(f) }
19
20
  spec.require_paths = ["lib"]
20
21
 
21
- spec.add_dependency "aws-sdk", "~> 2.2"
22
- spec.add_dependency "rails", ">= 4.2.0"
23
- spec.add_dependency "shoryuken", "~> 2.0"
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 "bundler", "~> 1.12"
26
- spec.add_development_dependency "rake", "~> 10.0"
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
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_RETRY: "1"
@@ -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 "rails", "~> 5.0.0"
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 :path => "../"
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 "rails", "~> 4.2.0"
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 :path => "../"
16
+ gemspec path: "../"
@@ -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
- require "aws-sdk"
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
- cwe_client: Aws::CloudWatchEvents::Client.new)
11
+ cwe_client: Aws::CloudWatchEvents::Client.new)
10
12
  @config = config
11
- @sqs_client, @cwe_client = sqs_client, cwe_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: task.rule_name,
32
+ name: task.rule_name,
43
33
  schedule_expression: task.rule_schedule_expression,
44
- state: "ENABLED",
45
- description: "CloudwatchScheduler task defined at #{task.code.source_location}"
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: task.rule_name,
39
+ rule: task.rule_name,
50
40
  targets: [
51
41
  {
52
- id: SecureRandom.uuid,
53
- arn: queue_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
- "Version": "2012-10-17",
64
- "Id": "#{queue_arn}/SQSDefaultPolicy",
65
- "Statement": rule_arns.map { |rule_arn|
53
+ Version: "2012-10-17",
54
+ Id: "#{queue_arn}/SQSDefaultPolicy",
55
+ Statement: rule_arns.map do |rule_arn|
66
56
  {
67
- "Sid": "TrustCWESendingToSQS",
68
- "Effect": "Allow",
69
- "Principal": {
70
- "AWS": "*"
57
+ Sid: "TrustCWESendingToSQS",
58
+ Effect: "Allow",
59
+ Principal: {
60
+ AWS: "*"
71
61
  },
72
- "Action": "sqs:SendMessage",
73
- "Resource": queue_arn,
74
- "Condition": {
75
- "ArnEquals": {
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: 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
- require 'active_support/core_ext/digest/uuid'
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: CloudwatchScheduler::Job.name,
28
- job_id: job_id,
30
+ job_class: CloudwatchScheduler::Job.name,
31
+ job_id: job_id,
29
32
  queue_name: CloudwatchScheduler::Job.queue_name,
30
- arguments: [name],
31
- locale: "en",
32
- priority: nil
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