cronitor 4.1.2 → 5.1.0
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/.github/workflows/publish.yml +5 -6
- data/.github/workflows/test.yml +21 -21
- data/.rubocop.yml +3 -0
- data/README.md +17 -7
- data/lib/cronitor/config.rb +14 -19
- data/lib/cronitor/monitor.rb +61 -28
- data/lib/cronitor/version.rb +1 -1
- data/lib/cronitor.rb +13 -30
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac1824833468d92068ba5664ef8d667fbe2518b34caa8da2cae3a307a7a923e7
|
4
|
+
data.tar.gz: 18ff6d1f48bd6da9686930585b6eaab3d296caedb33c171a5d668c26b69fdaba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d6e6aeaaaf3c0a8e5942132e833f53169756717dfa49d52d6641dc0a644f470cac6cc2124fdaebf12fb7814b485f9a14753c78a2a059541b94662c9127279a7
|
7
|
+
data.tar.gz: e2d4da41d199b4ff8c01fa768f69f0a48303c98559a2766f537b0a25f6940df21c0ecd2c94d4318636623f230cd8ff7976b75a3219ece9cae419b6eafa8b10ff
|
@@ -15,15 +15,14 @@ jobs:
|
|
15
15
|
runs-on: ubuntu-latest
|
16
16
|
|
17
17
|
steps:
|
18
|
-
- uses: actions/checkout@
|
19
|
-
- name: Set up Ruby
|
20
|
-
uses:
|
18
|
+
- uses: actions/checkout@v3
|
19
|
+
- name: Set up Ruby
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
21
|
with:
|
22
|
-
ruby-version: 2.7
|
22
|
+
ruby-version: 2.7
|
23
|
+
bundler-cache: true
|
23
24
|
- name: Build and test with Rake
|
24
25
|
run: |
|
25
|
-
gem install bundler
|
26
|
-
bundle install --jobs 4 --retry 3
|
27
26
|
bundle exec rake release
|
28
27
|
with:
|
29
28
|
api_key: ${{secrets.RUBYGEMS_API_KEY}}
|
data/.github/workflows/test.yml
CHANGED
@@ -10,25 +10,25 @@ on:
|
|
10
10
|
- master
|
11
11
|
|
12
12
|
jobs:
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
# lint:
|
14
|
+
# strategy:
|
15
|
+
# fail-fast: false
|
16
|
+
# matrix:
|
17
|
+
# ruby:
|
18
|
+
# - '2.7'
|
19
|
+
# - '3.0'
|
20
20
|
|
21
|
-
|
21
|
+
# runs-on: ubuntu-latest
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
# steps:
|
24
|
+
# - uses: actions/checkout@v2
|
25
|
+
# - name: Set up Ruby 2.7
|
26
|
+
# uses: ruby/setup-ruby@v1
|
27
|
+
# with:
|
28
|
+
# ruby-version: ${{ matrix.ruby }}
|
29
|
+
# bundler-cache: true
|
30
|
+
# - name: Run Rubocop
|
31
|
+
# run: bundle exec rake rubocop
|
32
32
|
|
33
33
|
spec:
|
34
34
|
strategy:
|
@@ -37,18 +37,18 @@ jobs:
|
|
37
37
|
ruby:
|
38
38
|
- '2.7'
|
39
39
|
- '3.0'
|
40
|
+
- '3.1'
|
41
|
+
- '3.2'
|
40
42
|
|
41
43
|
runs-on: ubuntu-latest
|
42
44
|
|
43
45
|
steps:
|
44
|
-
- uses: actions/checkout@
|
45
|
-
- name: Set up Ruby
|
46
|
+
- uses: actions/checkout@v3
|
47
|
+
- name: Set up Ruby
|
46
48
|
uses: ruby/setup-ruby@v1
|
47
49
|
with:
|
48
50
|
ruby-version: ${{ matrix.ruby }}
|
49
51
|
bundler-cache: true
|
50
52
|
- name: Build and test with Rake
|
51
53
|
run: |
|
52
|
-
gem install bundler
|
53
|
-
bundle install --jobs 4 --retry 3
|
54
54
|
bundle exec rake
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -29,8 +29,8 @@ The `Cronitor#job` helper will send telemetry events before calling your block a
|
|
29
29
|
require 'cronitor'
|
30
30
|
Cronitor.api_key = 'api_key_123'
|
31
31
|
|
32
|
-
Cronitor.job '
|
33
|
-
|
32
|
+
Cronitor.job 'important-job' do
|
33
|
+
ImportantJob.new(Date.today).run()
|
34
34
|
end
|
35
35
|
```
|
36
36
|
|
@@ -40,7 +40,7 @@ Cronitor provides a [separate library](https://github.com/cronitorio/cronitor-si
|
|
40
40
|
|
41
41
|
## Sending Telemetry Events
|
42
42
|
|
43
|
-
If you want
|
43
|
+
If you want more control over when/how [telemetry pings](https://cronitor.io/docs/telemetry-api) are sent,
|
44
44
|
you can instantiate a monitor and call `#ping`.
|
45
45
|
|
46
46
|
```ruby
|
@@ -69,7 +69,7 @@ a deployment or build process. For details on all of the attributes that can be
|
|
69
69
|
require 'cronitor'
|
70
70
|
Cronitor.api_key = 'api_key_123'
|
71
71
|
|
72
|
-
# read config file
|
72
|
+
# read config file.
|
73
73
|
Cronitor.read_config('./cronitor.yaml')
|
74
74
|
|
75
75
|
# sync config file's monitors to Cronitor.
|
@@ -78,6 +78,9 @@ Cronitor.apply_config
|
|
78
78
|
# send config file's monitors to Cronitor to validate correctness.
|
79
79
|
# monitors will not be saved.
|
80
80
|
Cronitor.validate_config
|
81
|
+
|
82
|
+
# generate a new config file from the Cronitor API.
|
83
|
+
Cronitor.generate_config
|
81
84
|
```
|
82
85
|
|
83
86
|
The `cronitor.yaml` file includes three top level keys `jobs`, `checks`, `heartbeats`. You can configure monitors under each key by defining [monitors](https://cronitor.io/docs/monitor-api#attributes).
|
@@ -129,7 +132,7 @@ You can also create and update monitors by calling `Monitor.put`.
|
|
129
132
|
```ruby
|
130
133
|
require 'cronitor'
|
131
134
|
|
132
|
-
monitors =
|
135
|
+
monitors = [
|
133
136
|
{
|
134
137
|
type: 'job',
|
135
138
|
key: 'send-customer-invoices',
|
@@ -145,13 +148,15 @@ monitors = Cronitor::Monitor.put([
|
|
145
148
|
request: {
|
146
149
|
url: 'https://cronitor.io'
|
147
150
|
},
|
148
|
-
schedule: 'every
|
151
|
+
schedule: 'every 60 seconds',
|
149
152
|
assertions: [
|
150
153
|
'response.code = 200',
|
151
154
|
'response.time < 600ms',
|
152
155
|
]
|
153
156
|
}
|
154
|
-
]
|
157
|
+
]
|
158
|
+
|
159
|
+
Cronitor::Monitor.put(monitors)
|
155
160
|
```
|
156
161
|
|
157
162
|
### Pause, Reset, Delete
|
@@ -178,6 +183,11 @@ require 'cronitor'
|
|
178
183
|
Cronitor.api_key = 'apiKey123'
|
179
184
|
Cronitor.api_version = '2020-10-01'
|
180
185
|
Cronitor.environment = 'cluster_1_prod'
|
186
|
+
|
187
|
+
Cronitor.timeout = 20 # defaults to 10 can also be set with ENV['CRONITOR_TIMEOUT']
|
188
|
+
Cronitor.logger = nil # defaults to Logger.new($stdout)
|
189
|
+
# faster timeout for potentially more time sensitive call
|
190
|
+
Cronitor.ping_timeout = 10 # defaults to 5 can also be set with ENV['CRONITOR_PING_TIMEOUT']
|
181
191
|
```
|
182
192
|
|
183
193
|
## Contributing
|
data/lib/cronitor/config.rb
CHANGED
@@ -1,33 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Cronitor
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
api_version
|
11
|
-
environment
|
12
|
-
] + MONITOR_TYPES.map { |t| "#{t}s" }
|
4
|
+
MONITOR_TYPES = [
|
5
|
+
TYPE_JOB = 'job',
|
6
|
+
TYPE_HEARTBEAT = 'heartbeat',
|
7
|
+
TYPE_CHECK = 'check'
|
8
|
+
].freeze
|
9
|
+
YAML_KEYS = MONITOR_TYPES.map { |t| "#{t}s" }
|
13
10
|
|
14
11
|
class << self
|
15
|
-
attr_accessor :api_key, :api_version, :environment, :logger, :config, :
|
12
|
+
attr_accessor :api_key, :api_version, :environment, :logger, :config, :timeout, :ping_timeout, :auto_discover_sidekiq
|
16
13
|
|
17
14
|
def configure(&block)
|
18
15
|
block.call(self)
|
19
16
|
end
|
20
17
|
end
|
21
18
|
|
22
|
-
self.api_key = ENV
|
23
|
-
self.api_version = ENV
|
24
|
-
self.environment = ENV
|
25
|
-
self.
|
19
|
+
self.api_key = ENV.fetch('CRONITOR_API_KEY', nil)
|
20
|
+
self.api_version = ENV.fetch('CRONITOR_API_VERSION', nil)
|
21
|
+
self.environment = ENV.fetch('CRONITOR_ENVIRONMENT', nil)
|
22
|
+
self.timeout = ENV.fetch('CRONITOR_TIMEOUT', nil) || 10
|
23
|
+
self.ping_timeout = ENV.fetch('CRONITOR_PING_TIMEOUT', nil) || 5
|
24
|
+
self.config = ENV.fetch('CRONITOR_CONFIG', nil)
|
25
|
+
self.auto_discover_sidekiq = ENV.fetch('CRONITOR_AUTO_DISCOVER_SIDEKIQ', 'true').casecmp('true').zero? # https://github.com/cronitorio/cronitor-sidekiq
|
26
26
|
self.logger = Logger.new($stdout)
|
27
27
|
logger.level = Logger::INFO
|
28
|
-
self._headers = {
|
29
|
-
'Content-Type': 'application/json',
|
30
|
-
'User-Agent': 'cronitor-ruby',
|
31
|
-
'Cronitor-Version': Cronitor.api_version
|
32
|
-
}
|
33
28
|
end
|
data/lib/cronitor/monitor.rb
CHANGED
@@ -6,56 +6,89 @@ module Cronitor
|
|
6
6
|
|
7
7
|
PING_RETRY_THRESHOLD = 5
|
8
8
|
|
9
|
+
module Formats
|
10
|
+
ALL = [
|
11
|
+
JSON = 'json',
|
12
|
+
YAML = 'yaml'
|
13
|
+
].freeze
|
14
|
+
end
|
15
|
+
|
16
|
+
module Headers
|
17
|
+
JSON = {
|
18
|
+
'Content-Type': 'application/json',
|
19
|
+
'User-Agent': "cronitor-ruby-#{Cronitor::VERSION}",
|
20
|
+
'Cronitor-Version': Cronitor.api_version
|
21
|
+
}.freeze
|
22
|
+
YAML = JSON.merge({
|
23
|
+
'Content-Type': 'application/yaml'
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
9
27
|
def self.put(opts = {})
|
10
28
|
rollback = opts[:rollback] || false
|
11
29
|
opts.delete(:rollback)
|
12
30
|
|
13
31
|
monitors = opts[:monitors] || [opts]
|
14
32
|
|
33
|
+
if opts[:format] == Cronitor::Monitor::Formats::YAML
|
34
|
+
url = "#{Cronitor.monitor_api_url}.yaml"
|
35
|
+
monitors['rollback'] = true if rollback
|
36
|
+
body = YAML.dump(monitors)
|
37
|
+
headers = Cronitor::Monitor::Headers::YAML
|
38
|
+
else
|
39
|
+
url = Cronitor.monitor_api_url
|
40
|
+
body = {
|
41
|
+
monitors: monitors,
|
42
|
+
rollback: rollback
|
43
|
+
}.to_json
|
44
|
+
headers = Cronitor::Monitor::Headers::JSON
|
45
|
+
end
|
46
|
+
|
15
47
|
resp = HTTParty.put(
|
16
|
-
|
48
|
+
url,
|
17
49
|
basic_auth: {
|
18
50
|
username: Cronitor.api_key,
|
19
51
|
password: ''
|
20
52
|
},
|
21
|
-
body:
|
22
|
-
|
23
|
-
|
24
|
-
}.to_json,
|
25
|
-
headers: Cronitor._headers,
|
26
|
-
timeout: opts[:timeout] || 10
|
53
|
+
body: body,
|
54
|
+
headers: headers,
|
55
|
+
timeout: opts[:timeout] || Cronitor.timeout
|
27
56
|
)
|
28
57
|
|
29
58
|
case resp.code
|
30
59
|
when 200
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
60
|
+
if opts[:format] == Cronitor::Monitor::Formats::YAML
|
61
|
+
YAML.safe_load(resp.body)
|
62
|
+
else
|
63
|
+
out = []
|
64
|
+
data = JSON.parse(resp.body)
|
65
|
+
|
66
|
+
(data['monitors'] || []).each do |md|
|
67
|
+
m = Monitor.new(md['key'])
|
68
|
+
m.data = Cronitor.symbolize_keys(md)
|
69
|
+
out << m
|
70
|
+
end
|
71
|
+
out.length == 1 ? out[0] : out
|
38
72
|
end
|
39
|
-
out.length == 1 ? out[0] : out
|
40
73
|
when 400
|
41
74
|
raise ValidationError.new(resp.body)
|
42
75
|
else
|
43
|
-
raise Error.new("Error connecting to Cronitor: #{resp.code}")
|
76
|
+
raise Error.new("Error connecting to Cronitor: #{resp.code}\n #{resp.body}")
|
44
77
|
end
|
45
78
|
end
|
46
79
|
|
47
80
|
def self.delete(key)
|
48
81
|
resp = HTTParty.delete(
|
49
82
|
"#{Cronitor.monitor_api_url}/#{key}",
|
50
|
-
timeout:
|
83
|
+
timeout: Cronitor.timeout,
|
51
84
|
basic_auth: {
|
52
85
|
username: Cronitor.api_key,
|
53
86
|
password: ''
|
54
87
|
},
|
55
|
-
headers: Cronitor
|
88
|
+
headers: Cronitor::Monitor::Headers::JSON
|
56
89
|
)
|
57
90
|
if resp.code != 204
|
58
|
-
Cronitor.logger
|
91
|
+
Cronitor.logger&.error("Error deleting monitor: #{key}")
|
59
92
|
return false
|
60
93
|
end
|
61
94
|
true
|
@@ -81,7 +114,7 @@ module Cronitor
|
|
81
114
|
def ping(params = {})
|
82
115
|
retry_count = params[:retry_count] || 0
|
83
116
|
if api_key.nil?
|
84
|
-
Cronitor.logger
|
117
|
+
Cronitor.logger&.error('No API key detected. Set Cronitor.api_key or initialize Monitor with an api_key:')
|
85
118
|
return false
|
86
119
|
end
|
87
120
|
|
@@ -92,8 +125,8 @@ module Cronitor
|
|
92
125
|
response = HTTParty.get(
|
93
126
|
ping_url,
|
94
127
|
query: clean_params(params),
|
95
|
-
timeout:
|
96
|
-
headers: Cronitor
|
128
|
+
timeout: Cronitor.ping_timeout,
|
129
|
+
headers: Cronitor::Monitor::Headers::JSON,
|
97
130
|
query_string_normalizer: lambda do |query|
|
98
131
|
query.compact!
|
99
132
|
metrics = query[:metric]
|
@@ -106,13 +139,13 @@ module Cronitor
|
|
106
139
|
)
|
107
140
|
|
108
141
|
if response.code != 200
|
109
|
-
Cronitor.logger
|
142
|
+
Cronitor.logger&.error("Cronitor Telemetry Error: #{response.code}")
|
110
143
|
return false
|
111
144
|
end
|
112
145
|
true
|
113
146
|
rescue StandardError => e
|
114
147
|
# rescue instances of StandardError i.e. Timeout::Error, SocketError, etc
|
115
|
-
Cronitor.logger
|
148
|
+
Cronitor.logger&.error("Cronitor Telemetry Error: #{e}")
|
116
149
|
return false if retry_count >= Monitor::PING_RETRY_THRESHOLD
|
117
150
|
|
118
151
|
# apply a backoff before sending the next ping
|
@@ -131,8 +164,8 @@ module Cronitor
|
|
131
164
|
|
132
165
|
resp = HTTParty.get(
|
133
166
|
pause_url,
|
134
|
-
timeout:
|
135
|
-
headers: Cronitor
|
167
|
+
timeout: Cronitor.timeout,
|
168
|
+
headers: Cronitor::Monitor::Headers::JSON,
|
136
169
|
basic_auth: {
|
137
170
|
username: api_key,
|
138
171
|
password: ''
|
@@ -162,13 +195,13 @@ module Cronitor
|
|
162
195
|
|
163
196
|
def fetch
|
164
197
|
unless api_key
|
165
|
-
Cronitor.logger
|
198
|
+
Cronitor.logger&.error(
|
166
199
|
'No API key detected. Set Cronitor.api_key or initialize Monitor with the api_key kwarg'
|
167
200
|
)
|
168
201
|
return
|
169
202
|
end
|
170
203
|
|
171
|
-
HTTParty.get(monitor_api_url, timeout:
|
204
|
+
HTTParty.get(monitor_api_url, timeout: Cronitor.timeout, headers: Cronitor::Monitor::Headers::JSON, format: :json)
|
172
205
|
end
|
173
206
|
|
174
207
|
def clean_params(params)
|
data/lib/cronitor/version.rb
CHANGED
data/lib/cronitor.rb
CHANGED
@@ -13,7 +13,7 @@ require 'cronitor/version'
|
|
13
13
|
require 'cronitor/monitor'
|
14
14
|
|
15
15
|
module Cronitor
|
16
|
-
def self.read_config(path = nil
|
16
|
+
def self.read_config(path = nil)
|
17
17
|
Cronitor.config = path || Cronitor.config
|
18
18
|
unless Cronitor.config
|
19
19
|
raise ConfigurationError.new(
|
@@ -26,40 +26,23 @@ module Cronitor
|
|
26
26
|
conf.each do |k, _v|
|
27
27
|
raise ConfigurationError.new("Invalid configuration variable: #{k}") unless Cronitor::YAML_KEYS.include?(k)
|
28
28
|
end
|
29
|
-
|
30
|
-
Cronitor.api_key = conf[:api_key] if conf[:api_key]
|
31
|
-
Cronitor.api_version = conf[:api_version] if conf[:api_version]
|
32
|
-
Cronitor.environment = conf[:environment] if conf[:environment]
|
33
|
-
|
34
|
-
return unless output
|
35
|
-
|
36
|
-
monitors = []
|
37
|
-
Cronitor::MONITOR_TYPES.each do |t|
|
38
|
-
plural_t = "#{t}s"
|
39
|
-
to_parse = conf[t] || conf[plural_t] || nil
|
40
|
-
next unless to_parse
|
41
|
-
|
42
|
-
unless to_parse.is_a?(Hash)
|
43
|
-
raise ConfigurationError.new('A Hash with keys corresponding to monitor keys is expected.')
|
44
|
-
end
|
45
|
-
|
46
|
-
to_parse.each do |key, m|
|
47
|
-
m['key'] = key
|
48
|
-
m['type'] = t
|
49
|
-
monitors << m
|
50
|
-
end
|
51
|
-
end
|
52
|
-
conf['monitors'] = monitors
|
53
29
|
conf
|
54
30
|
end
|
55
31
|
|
56
32
|
def self.apply_config(rollback: false)
|
57
|
-
conf = read_config
|
58
|
-
# allow a significantly longer timeout on requests that are sending full yaml config
|
59
|
-
|
60
|
-
|
33
|
+
conf = read_config
|
34
|
+
# allow a significantly longer timeout on requests that are sending full yaml config. min 30 seconds.
|
35
|
+
timeout = Cronitor.timeout < 30 ? 30 : Cronitor.timeout
|
36
|
+
monitors = Monitor.put(monitors: conf, format: Cronitor::Monitor::Formats::YAML, rollback: rollback,
|
37
|
+
timeout: timeout)
|
38
|
+
count = 0
|
39
|
+
# step through the different monitor types and count up all the returned configurations
|
40
|
+
Cronitor::YAML_KEYS.each do |k|
|
41
|
+
count += (monitors[k]&.count || 0)
|
42
|
+
end
|
43
|
+
puts("#{count} monitors #{rollback ? 'validated' : 'synced to Cronitor'}.")
|
61
44
|
rescue ValidationError => e
|
62
|
-
Cronitor.logger
|
45
|
+
Cronitor.logger&.error(e)
|
63
46
|
end
|
64
47
|
|
65
48
|
def self.validate_config
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cronitor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Byrnes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-03-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httparty
|