sidekiq-cronitor 2.0.0 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77c9e01c256be04515fbd21f7e467fb28e632a37f94d639847c6af8ad6e9823b
4
- data.tar.gz: 2c78645ae3fb16b98b52777b3b3124aaa76e6860fc606bee2bc2ab8696275663
3
+ metadata.gz: 7fdd6b7a4900b0b4325bdecbb6774f71748e20d81aa44969b4687e6ee833e4b2
4
+ data.tar.gz: f61d0a3051c15d95d000273bca3b2f127e70d16a28e2769a19bf976a4e47f088
5
5
  SHA512:
6
- metadata.gz: 70c63ea8977ac11afe3991a1290950ed1deaa95c0147e8434fc3d0cf0fd4ed965d6d31354b150ae74e505497d7a5499023ea93f41a7eeca14fdddefc2a38a2c7
7
- data.tar.gz: 6474a1e11df5373147b252fe327373e084f34abb60b6708f99c81df6b1c6d37643642228f1651fca7ddc4d9c0b988abec2f6a045f949f3e0a8e07dd5cc953b30
6
+ metadata.gz: 1f687f12236ef9af2041ff33a0ba5df7bdb378ee316ff84ce0c7ae298ab018a973ee168a88eadc07cc4a9d86a3d6ceca9d006a0a166c9f7e4d90462444e70720
7
+ data.tar.gz: b3d78f111182e36d322c1eaa41f7297b1bddcf286e8240780de2be6092ebd39c36ba9b708b4e013cde8fb8327c751f0a86e73d266951ea4978d5cd72e11c8f34
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # Sidekiq Cronitor
2
2
 
3
- Call a [Cronitor](https://cronitor.io) around your [Sidekiq](https://sidekiq.org) jobs.
3
+ [Cronitor](https://cronitor.io/) provides dead simple monitoring for cron jobs, daemons, queue workers, websites, APIs, and anything else that can send or receive an HTTP request. The Cronitor Sidekiq library provides a drop in integration for monitoring any Sidekiq Job.
4
+
5
+
6
+ #### NOTE: Version 3.0.0 changes the integration method from 2.x.x. This is a breaking change. You now add the middleware in the Sidekiq initializer. You can opt of out telemetry for specific jobs with a sidekiq_options (see below)
4
7
 
5
8
  ## Installation
6
9
 
@@ -19,43 +22,96 @@ bundle
19
22
 
20
23
  ## Usage
21
24
 
22
- Make sure you've got a Cronitor [API Key](https://cronitor.io/docs/api-overview) from [your settings](https://cronitor.io/settings) in your ENV as `CRONITOR_API_KEY` before starting Sidekiq:
25
+ Configure `sidekiq-cronitor` with an [API Key](https://cronitor.io/docs/api-overview) from [your settings](https://cronitor.io/settings). You can use ENV variables to configure Cronitor:
23
26
 
24
27
  ```sh
25
- export CRONITOR_API_KEY='abcdef1234567890abcdef1234567890'
28
+ export CRONITOR_API_KEY='api_key_123'
29
+ export CRONITOR_ENVIRONMENT='development' #default: 'production'
30
+
26
31
  bundle exec sidekiq
27
32
  ```
28
33
 
29
- Any sidekiq worker you'd like to monitor just includes `Sidekiq::Cronitor` right after `Sidekiq::Worker`:
34
+ Or declare the API key directly on the Cronitor module from within your application (e.g. the Sidekiq initializer).
30
35
 
31
36
  ```ruby
32
- class MyWorker
33
- include Sidekiq::Worker
34
- include Sidekiq::Cronitor
37
+ require 'cronitor'
38
+ Cronitor.api_key = 'api_key_123'
39
+ Cronitor.environment = 'development' #default: 'production'
40
+ ```
35
41
 
36
- def perform
37
- # ...
42
+
43
+ To monitor jobs insert the server middleware (most people do this in the Sidekiq initializer)
44
+
45
+ ```ruby
46
+ Sidekiq.configure_server do |config|
47
+ config.server_middleware do |chain|
48
+ chain.add Sidekiq::Cronitor::ServerMiddleware
38
49
  end
39
50
  end
40
51
  ```
41
52
 
42
- By default this will look for an existing monitor named after your worker, `MyWorker` in the case above, and pings that. Otherwise it will try to create a new monitor with the worker's name, which you can configure rules for at a later time via your Cronitor dashboard.
43
53
 
44
- To use a monitor you've already created, you can configure the monitor's `key` directly:
54
+ When this job is invoked, Cronitor will send telemetry pings with a `key` matching the name of your job class (`MyJob` in the example below). If no monitor exists it will create one on the first event. You can configure rules at a later time via the Cronitor dashboard, API, or [YAML config](https://github.com/cronitorio/cronitor-ruby#configuring-monitors) file.
55
+
56
+ Optional: You can specify the monitor key directly using `sidekiq_options`:
45
57
 
46
58
  ```ruby
47
- class MyWorker
48
- include Sidekiq::Worker
49
- include Sidekiq::Cronitor
59
+ class MyJob
60
+ include Sidekiq::Job
61
+ sidekiq_options cronitor_key: 'abc123'
62
+
63
+ def perform
64
+ end
65
+ end
66
+ ```
67
+
50
68
 
51
- sidekiq_options cronitor: { key: 'abc123' }
69
+ To disable Cronitor for a specific job you can set the following option:
70
+
71
+ ```ruby
72
+ class MyJob
73
+ include Sidekiq::Job
74
+ sidekiq_options cronitor_disabled: true
52
75
 
53
76
  def perform
54
- # ...
55
77
  end
56
78
  end
57
79
  ```
58
80
 
81
+ ## Disabling For Some Jobs
82
+ If you have an entire group or category of jobs you wish to disable monitoring on, it's easiest to create a base class with that option set and then have all your jobs inherit from that base class.
83
+
84
+ ```ruby
85
+ class UnmonitoredJob
86
+ include Sidekiq::Job
87
+ sidekiq_options cronitor_disabled: true
88
+ end
89
+
90
+ class NoInstrumentationJob < UnmonitoredJob
91
+ def perform
92
+ end
93
+ end
94
+ ```
95
+
96
+ Note: Do NOT set a cronitor_key option on your base class or all your inherited jobs will report under the same job in Cronitor.
97
+
98
+ ## Job Monitoring
99
+ If you are using Cronitor to monitor scheduled/periodic jobs and have jobs schedules already defined you can use rake tasks to upload the schedule to Cronitor for monitoring.
100
+
101
+ In your projects Rakefile you can load the task to be available to you in your project.
102
+ It might be a good idea to sync these schedules on every deploy
103
+
104
+ ```ruby
105
+ # your Rakefile, find the path to the gem
106
+ spec = Gem::Specification.find_by_name 'sidekiq-cronitor'
107
+ # if you are using sidekiq_scheduler this task should parse and upload the schedule.
108
+ load "#{spec.gem_dir}/lib/tasks/sidekiq_scheduler.rake"
109
+ # if you are using Sidekiq Pro Periodic Jobs this is an example script
110
+ # Note: this hasn't been tested on Sidekiq Pro yet
111
+ load "#{spec.gem_dir}/lib/tasks/periodic_jobs.rake"
112
+ # You only really need to load one of the rake files unless you are somehow running both systems
113
+ ```
114
+
59
115
  ## Development
60
116
 
61
117
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,14 @@
1
+ module Sidekiq::Cronitor
2
+ class PeriodicJobs
3
+ def self.sync_schedule!
4
+ monitors_payload = []
5
+ loops = Sidekiq::Periodic::LoopSet.new
6
+ loops.each do |lop|
7
+ job_key = lop.klass.sidekiq_options.fetch("cronitor_key", nil) || lop.klass.to_s
8
+ cronitor_disabled = lop.klass.sidekiq_options.fetch("cronitor_disabled", false)
9
+ monitors_payload << {key: job_key, schedule: lop.schedule, metadata: lop.options, platform: 'sidekiq', type: 'job' } unless cronitor_disabled
10
+ end
11
+ Cronitor::Monitor.put(monitors: monitors_payload)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module Sidekiq::Cronitor
2
+ class SidekiqScheduler
3
+ def self.sync_schedule!
4
+ monitors_payload = []
5
+ # go through the scheduled jobs and find cron defined ones
6
+ Sidekiq.get_schedule.each do |k, v|
7
+ # make sure the job has a cron or every definition, we skip non cron/every defined jobs for now
8
+ if !v["cron"].nil? || !v["every"].nil?
9
+ schedule = v["cron"] || v["every"]
10
+ # just in case an explicit job key has been set
11
+ job_klass = Object.const_get(v["class"])
12
+ job_key = job_klass.sidekiq_options.fetch("cronitor_key", nil) || v["class"]
13
+ # if monitoring for this job is turned off
14
+ cronitor_disabled = job_klass.sidekiq_options.fetch("cronitor_disabled", false)
15
+ monitors_payload << {key: job_key.to_s, schedule: schedule, platform: 'sidekiq', type: 'job' } unless cronitor_disabled
16
+ end
17
+ end
18
+ Cronitor::Monitor.put(monitors: monitors_payload)
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Cronitor
3
- VERSION = '2.0.0'
3
+ VERSION = '3.1.1'
4
4
  end
5
5
  end
@@ -3,75 +3,72 @@ require 'cronitor'
3
3
 
4
4
  require 'sidekiq/cronitor/version'
5
5
 
6
- module Sidekiq::Cronitor
7
- def self.included(base)
8
- unless base.ancestors.include?(Sidekiq::Worker)
9
- raise ArgumentError, 'Sidekiq::Cronitor can only be included in a Sidekiq::Worker'
10
- end
11
-
12
- base.extend(ClassMethods)
13
-
14
- # Automatically add sidekiq middleware when we're first included
15
- Sidekiq.configure_server do |config|
16
- unless config.server_middleware.exists?(Sidekiq::Cronitor::Middleware)
17
- config.server_middleware.add(Sidekiq::Cronitor::Middleware)
18
- end
19
- end
20
- end
21
-
22
- def cronitor
23
- self.class.cronitor
24
- end
25
-
26
- module ClassMethods
27
- def cronitor
28
- return @cronitor if defined?(@cronitor)
29
-
30
- opts = sidekiq_options.fetch('cronitor', {})
31
- key = opts.symbolize_keys.fetch(:key, name)
32
-
33
- Sidekiq.logger.debug("[cronitor] initializing monitor: worker=#{name} key=#{key}")
34
-
35
- begin
36
- @cronitor = Cronitor::Monitor.new(key)
37
- rescue Cronitor::Error => e
38
- Sidekiq.logger.error("[cronitor] failed to initialize monitor: worker=#{name} error=#{e.message}")
6
+ if defined? SidekiqScheduler
7
+ require 'sidekiq/cronitor/sidekiq_scheduler'
8
+ end
39
9
 
40
- @cronitor = nil
41
- end
42
- end
43
- end
10
+ if defined? Sidekiq::Periodic
11
+ require 'sidekiq/cronitor/periodic_jobs'
12
+ end
44
13
 
45
- class Middleware
14
+ module Sidekiq::Cronitor
15
+ class ServerMiddleware
46
16
  def call(worker, message, queue)
47
17
  ping(worker: worker, state: 'run')
48
18
 
49
- yield
19
+ result = yield
50
20
  rescue => e
51
21
  ping(worker: worker, state: 'fail', message: e.to_s)
52
22
 
53
23
  raise e
54
24
  else
55
25
  ping(worker: worker, state: 'complete')
26
+ result # to be consistent with client middleware, return results of yield
56
27
  end
57
28
 
58
29
  private
30
+ def cronitor(worker)
31
+ Cronitor::Monitor.new(job_key(worker))
32
+ end
33
+
34
+ def cronitor_disabled?(worker)
35
+ disabled = worker.class.sidekiq_options.fetch("cronitor_disabled", nil)
36
+ if disabled.nil?
37
+ options(worker).fetch(:disabled, false)
38
+ else
39
+ !!disabled
40
+ end
41
+ end
42
+
43
+ def job_key(worker)
44
+ worker.class.sidekiq_options.fetch("cronitor_key", nil) ||
45
+ options(worker).fetch(:key, worker.class.name)
46
+ end
47
+
48
+ def options(worker)
49
+ # eventually we will delete this method of passing options
50
+ # ultimately we want all cronitor options to be top level keys
51
+ opts = worker.class.sidekiq_options.fetch("cronitor", {})
52
+ # symbolize_keys is a rails helper, so only use it if it's defined
53
+ opts = opts.symbolize_keys if opts.respond_to?(:symbolize_keys)
54
+ opts
55
+ end
59
56
 
60
57
  def ping(worker:, state:, message: nil)
61
- return unless has_cronitor?(worker)
58
+ return unless should_ping?(worker)
62
59
 
63
- Sidekiq.logger.debug("[cronitor] ping: worker=#{worker.class.name} state=#{state} message=#{message}")
60
+ Sidekiq.logger.debug("[cronitor] ping: worker=#{job_key(worker)} state=#{state} message=#{message}")
64
61
 
65
- worker.cronitor.ping(state: state)
62
+ cronitor(worker).ping(state: state)
66
63
  rescue Cronitor::Error => e
67
- Sidekiq.logger.error("[cronitor] error during ping: worker=#{worker.class.name} error=#{e.message}")
64
+ Sidekiq.logger.error("[cronitor] error during ping: worker=#{job_key(worker)} error=#{e.message}")
68
65
  rescue => e
69
- Sidekiq.logger.error("[cronitor] unexpected error: worker=#{worker.class.name} error=#{e.message}")
66
+ Sidekiq.logger.error("[cronitor] unexpected error: worker=#{job_key(worker)} error=#{e.message}")
70
67
  Sidekiq.logger.error(e.backtrace.first)
71
68
  end
72
69
 
73
- def has_cronitor?(worker)
74
- worker.is_a?(Sidekiq::Cronitor) && worker.respond_to?(:cronitor) && !worker.cronitor.api_key.nil?
70
+ def should_ping?(worker)
71
+ !cronitor(worker).api_key.nil? && !cronitor_disabled?(worker)
75
72
  end
76
73
  end
77
74
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-cronitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zeke Gabrielse
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-05-11 00:00:00.000000000 Z
12
+ date: 2022-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq
@@ -107,6 +107,8 @@ files:
107
107
  - LICENSE
108
108
  - README.md
109
109
  - lib/sidekiq/cronitor.rb
110
+ - lib/sidekiq/cronitor/periodic_jobs.rb
111
+ - lib/sidekiq/cronitor/sidekiq_scheduler.rb
110
112
  - lib/sidekiq/cronitor/version.rb
111
113
  homepage: https://github.com/cronitor/sidekiq-cronitor
112
114
  licenses: