jobtick 0.1.0 → 0.1.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/README.md +34 -18
- data/lib/jobtick/client.rb +4 -2
- data/lib/jobtick/hooks/active_job.rb +18 -0
- data/lib/jobtick/middleware/sidekiq.rb +25 -0
- data/lib/jobtick/railtie.rb +3 -0
- data/lib/jobtick/registry.rb +6 -1
- data/lib/jobtick/version.rb +1 -1
- data/lib/jobtick.rb +15 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dff65ac46c3a2ce39e670a9b940726f11e7f72ab5695812031417097fbf6e2d6
|
|
4
|
+
data.tar.gz: bb6044dd0c4c43c9e956de1eec4a5f2032ba6787aebfb9f1ddae8267ff79c35a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 80ac95fe4fa508de3656ed0cc187657e9e3c2be0f68a76451dc4e1b0633a51b81e4f86ec0665163278daeb12d64e374f0496f6a1c1c7596aac673519cdc6fc87
|
|
7
|
+
data.tar.gz: c0ce19f6cc1b5cf3f7bad98a38448bf012dafb09dd74fade6934b797ab94f05f82971d5e49cad5a3067f862b29d3cb65f373d8b139468d5912cbc7f7cdb15271
|
data/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# JobTick
|
|
2
2
|
|
|
3
|
+
[](https://github.com/clearstack-labs/jobtick/actions/workflows/main.yml)
|
|
4
|
+
|
|
3
5
|
**Rails job monitoring for Whenever, Solid Queue, and Sidekiq.**
|
|
4
6
|
Know when your scheduled jobs stop running — before your users do.
|
|
5
7
|
|
|
@@ -59,21 +61,6 @@ No changes to individual job files. No manual monitor creation. No names to keep
|
|
|
59
61
|
|
|
60
62
|
## What gets monitored
|
|
61
63
|
|
|
62
|
-
### Whenever (`config/schedule.rb`)
|
|
63
|
-
|
|
64
|
-
```ruby
|
|
65
|
-
# Your existing schedule.rb — no changes needed
|
|
66
|
-
every 1.day, at: '2:00 am' do
|
|
67
|
-
runner 'InvoiceJob.perform_later'
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
every :hour do
|
|
71
|
-
runner 'SyncInventoryJob.perform_later'
|
|
72
|
-
end
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
JobTick reads this file at deploy time and creates a monitor for each job automatically.
|
|
76
|
-
|
|
77
64
|
### Solid Queue (`config/recurring.yml`)
|
|
78
65
|
|
|
79
66
|
```yaml
|
|
@@ -87,12 +74,17 @@ sync_exchange_rates:
|
|
|
87
74
|
schedule: every hour
|
|
88
75
|
```
|
|
89
76
|
|
|
90
|
-
|
|
77
|
+
At boot, JobTick reads this file and registers a monitor for each entry. It then installs an `around_perform` hook into `ActiveJob::Base` so every job execution automatically sends `started`, `completed`, and `failed` pings. No changes to your job files.
|
|
91
78
|
|
|
92
79
|
### Sidekiq periodic jobs
|
|
93
80
|
|
|
81
|
+
Supports both **sidekiq-cron** and **Sidekiq::Periodic**:
|
|
82
|
+
|
|
94
83
|
```ruby
|
|
95
|
-
#
|
|
84
|
+
# sidekiq-cron — loaded from config/sidekiq_cron.yml or in an initializer
|
|
85
|
+
Sidekiq::Cron::Job.create(name: 'Nightly Cleanup', cron: '0 2 * * *', class: 'NightlyCleanupWorker')
|
|
86
|
+
|
|
87
|
+
# Sidekiq::Periodic
|
|
96
88
|
Sidekiq.configure_server do |config|
|
|
97
89
|
config.periodic do |mgr|
|
|
98
90
|
mgr.register('0 * * * *', HourlyDigestWorker)
|
|
@@ -101,6 +93,30 @@ Sidekiq.configure_server do |config|
|
|
|
101
93
|
end
|
|
102
94
|
```
|
|
103
95
|
|
|
96
|
+
JobTick installs a server middleware that wraps every job execution. For native Sidekiq workers (`Sidekiq::Worker` subclasses) pings are sent by the middleware. For Active Job workers dispatched through Sidekiq, pings are sent by the `around_perform` hook instead, so nothing is double-counted.
|
|
97
|
+
|
|
98
|
+
### Whenever (`config/schedule.rb`)
|
|
99
|
+
|
|
100
|
+
Whenever schedules jobs as cron shell commands, so there is no Ruby hook point to instrument automatically. One setup step is required: run the generator and update your `config/schedule.rb` to use the `jobtick_runner` and `jobtick_rake` job types instead of the built-in `runner` and `rake`:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
bundle exec rake jobtick:whenever:setup
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This prints the two `job_type` definitions to add to the top of your schedule file, then use them in place of the standard types:
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
every 1.day, at: '2:00 am' do
|
|
110
|
+
jobtick_runner 'InvoiceJob.perform_later', monitor_key: 'whenever.invoice_job'
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
every :hour do
|
|
114
|
+
jobtick_rake 'reports:sync', monitor_key: 'whenever.reports_sync'
|
|
115
|
+
end
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The job types wrap execution with `curl` pings to the JobTick API, so no changes to individual job classes are needed.
|
|
119
|
+
|
|
104
120
|
---
|
|
105
121
|
|
|
106
122
|
## What you get
|
|
@@ -119,7 +135,7 @@ end
|
|
|
119
135
|
|
|
120
136
|
## Requirements
|
|
121
137
|
|
|
122
|
-
- Ruby >= 3.
|
|
138
|
+
- Ruby >= 3.3
|
|
123
139
|
- Rails >= 7.0
|
|
124
140
|
- One or more of: Whenever, Solid Queue, Sidekiq
|
|
125
141
|
|
data/lib/jobtick/client.rb
CHANGED
|
@@ -19,11 +19,13 @@ module JobTick
|
|
|
19
19
|
post("/ping/#{monitor_key}", payload)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def register(monitors)
|
|
22
|
+
def register(monitors, app_name: nil)
|
|
23
23
|
return unless JobTick.config.enabled
|
|
24
24
|
return if JobTick.config.api_key.nil?
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
payload = { monitors: monitors }
|
|
27
|
+
payload[:app_name] = app_name if app_name && !app_name.empty?
|
|
28
|
+
post("/monitors/sync", payload)
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
private
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JobTick
|
|
4
|
+
module Hooks
|
|
5
|
+
module ActiveJob
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.around_perform do |job, block|
|
|
8
|
+
key = JobTick.monitor_key_for(job.class.name)
|
|
9
|
+
if key
|
|
10
|
+
JobTick::Monitor.run(key) { block.call }
|
|
11
|
+
else
|
|
12
|
+
block.call
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JobTick
|
|
4
|
+
module Middleware
|
|
5
|
+
class Sidekiq
|
|
6
|
+
def call(_worker, job, _queue)
|
|
7
|
+
# Active Job wrappers are handled by the around_perform hook
|
|
8
|
+
return yield if job["wrapped"]
|
|
9
|
+
|
|
10
|
+
key = JobTick.monitor_key_for(job["class"])
|
|
11
|
+
return yield unless key
|
|
12
|
+
|
|
13
|
+
JobTick::Monitor.run(key) { yield }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.install
|
|
17
|
+
::Sidekiq.configure_server do |config|
|
|
18
|
+
config.server_middleware do |chain|
|
|
19
|
+
chain.add(JobTick::Middleware::Sidekiq)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/jobtick/railtie.rb
CHANGED
data/lib/jobtick/registry.rb
CHANGED
|
@@ -9,9 +9,14 @@ module JobTick
|
|
|
9
9
|
Parsers::Sidekiq.parse
|
|
10
10
|
].flatten.compact
|
|
11
11
|
|
|
12
|
+
JobTick.monitor_map = monitors.each_with_object({}) do |m, map|
|
|
13
|
+
map[m[:task]] = m[:key] if m[:task]
|
|
14
|
+
end
|
|
15
|
+
|
|
12
16
|
return [] if monitors.empty?
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
app_name = Rails.application.class.module_parent_name if defined?(Rails)
|
|
19
|
+
JobTick.client.register(monitors, app_name: app_name)
|
|
15
20
|
monitors
|
|
16
21
|
end
|
|
17
22
|
end
|
data/lib/jobtick/version.rb
CHANGED
data/lib/jobtick.rb
CHANGED
|
@@ -9,6 +9,8 @@ require_relative "jobtick/parsers/whenever"
|
|
|
9
9
|
require_relative "jobtick/parsers/solid_queue"
|
|
10
10
|
require_relative "jobtick/parsers/sidekiq"
|
|
11
11
|
require_relative "jobtick/registry"
|
|
12
|
+
require_relative "jobtick/hooks/active_job"
|
|
13
|
+
require_relative "jobtick/middleware/sidekiq"
|
|
12
14
|
require_relative "jobtick/railtie" if defined?(Rails::Railtie)
|
|
13
15
|
|
|
14
16
|
module JobTick
|
|
@@ -31,9 +33,22 @@ module JobTick
|
|
|
31
33
|
defined?(Rails) ? Rails.logger : Logger.new($stdout)
|
|
32
34
|
end
|
|
33
35
|
|
|
36
|
+
def monitor_map
|
|
37
|
+
@monitor_map ||= {}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def monitor_map=(map)
|
|
41
|
+
@monitor_map = map
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def monitor_key_for(class_name)
|
|
45
|
+
monitor_map[class_name.to_s]
|
|
46
|
+
end
|
|
47
|
+
|
|
34
48
|
def reset!
|
|
35
49
|
@config = nil
|
|
36
50
|
@client = nil
|
|
51
|
+
@monitor_map = {}
|
|
37
52
|
end
|
|
38
53
|
end
|
|
39
54
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jobtick
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Clearstack Labs
|
|
@@ -39,6 +39,8 @@ files:
|
|
|
39
39
|
- lib/jobtick.rb
|
|
40
40
|
- lib/jobtick/client.rb
|
|
41
41
|
- lib/jobtick/configuration.rb
|
|
42
|
+
- lib/jobtick/hooks/active_job.rb
|
|
43
|
+
- lib/jobtick/middleware/sidekiq.rb
|
|
42
44
|
- lib/jobtick/monitor.rb
|
|
43
45
|
- lib/jobtick/parsers/sidekiq.rb
|
|
44
46
|
- lib/jobtick/parsers/solid_queue.rb
|