jobtick 0.1.4 → 0.2.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/CHANGELOG.md +20 -0
- data/README.md +32 -0
- data/lib/jobtick/client.rb +9 -30
- data/lib/jobtick/configuration.rb +8 -1
- data/lib/jobtick/dispatcher.rb +193 -0
- data/lib/jobtick/hooks/active_job.rb +1 -1
- data/lib/jobtick/middleware/sidekiq.rb +1 -1
- data/lib/jobtick/monitor.rb +10 -6
- data/lib/jobtick/parsers/sidekiq.rb +4 -1
- data/lib/jobtick/parsers/solid_queue.rb +3 -3
- data/lib/jobtick/railtie.rb +7 -0
- data/lib/jobtick/registry.rb +3 -3
- data/lib/jobtick/version.rb +1 -1
- data/lib/jobtick.rb +5 -8
- data/lib/tasks/jobtick.rake +5 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: abfce9cfddae0a798d132217b9376b130afe9446f85e279d3241e7016ed1a89f
|
|
4
|
+
data.tar.gz: 36590511cdf6e5b07541cdb66589fc5efd7f2250aeb4d5e5e4b20a18976642de
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a81d1bf56a1e48ed5395bd5d913b8f49aafa163095261e7f066182f138c71f00259d7e428c5ee5a4e685a4320464aecd66aedde77a1f4c41cbb8431491999a39
|
|
7
|
+
data.tar.gz: f1fc3adfece35b9253e59be4beab12c5b2e1292c8330f287a386f37a71715d9cda922ca216a5219052e7097e1db13404b23c8118a10203fdbbf4024f37651e51
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## [0.2.0] - 2026-05-28
|
|
2
|
+
|
|
3
|
+
- Performance: pings are now dispatched asynchronously on a single daemon thread, so job workers no longer block on network I/O. A persistent, keep-alive HTTPS connection is reused for all pings (no more TCP/TLS handshake per ping).
|
|
4
|
+
- Performance: switch to `Process.clock_gettime(CLOCK_MONOTONIC)` for duration measurement — no `Time` object allocation per job, and immune to wall-clock jumps.
|
|
5
|
+
- Performance: lazy-load parsers, hooks, middleware, and the registry — only Rails boots that have JobTick enabled pay for them.
|
|
6
|
+
- Performance: the monitor map is frozen after sync, and parser allocations are trimmed on the boot path.
|
|
7
|
+
- Add `Configuration#queue_limit` (default 1000) to bound the background ping queue; over-limit pings are dropped non-blockingly rather than back-pressuring the job thread.
|
|
8
|
+
|
|
9
|
+
### Measured impact
|
|
10
|
+
|
|
11
|
+
Benchmarked with `spec/benchmarks/monitor_bench.rb` (10,000 iterations, WebMock-stubbed endpoint so the numbers reflect gem-internal overhead, not real network latency):
|
|
12
|
+
|
|
13
|
+
| Metric (per monitored job) | v0.1.4 | v0.2.0 | Change |
|
|
14
|
+
|---|---:|---:|---:|
|
|
15
|
+
| Job-thread blocking time | 400.6 µs | 2.0 µs | **~200× faster** |
|
|
16
|
+
| Object allocations on job thread | 2,390 | 9 | **~265× fewer** |
|
|
17
|
+
| End-to-end CPU time (incl. background dispatch) | 400.6 µs | 18.1 µs | **~22× less CPU** |
|
|
18
|
+
|
|
19
|
+
In production, where each ping pays real network RTT, the job-thread speedup is significantly larger: a single 20 ms RTT × 2–3 pings per job is ~50 ms blocking under v0.1.4, versus ~2 µs under v0.2.0 (~25,000× on the worker thread). Run `bundle exec ruby spec/benchmarks/monitor_bench.rb [iterations]` to reproduce.
|
|
20
|
+
|
|
1
21
|
## [0.1.4] - 2026-05-05
|
|
2
22
|
|
|
3
23
|
- Add `prune` configuration option — when enabled, monitors absent from the latest sync payload are permanently deleted, keeping the dashboard in sync with your schedule config
|
data/README.md
CHANGED
|
@@ -58,6 +58,38 @@ That's it. On next deploy, JobTick reads your schedule config, registers a monit
|
|
|
58
58
|
|
|
59
59
|
No changes to individual job files. No manual monitor creation. No names to keep in sync.
|
|
60
60
|
|
|
61
|
+
### Environments
|
|
62
|
+
|
|
63
|
+
**JobTick is only active in production by default.** In `development`, `staging`, or any other environment it silently does nothing — no pings are sent, no monitors are registered, no errors are raised. This means you can deploy the gem and configure it without worrying about local runs polluting your monitors or counting toward your plan.
|
|
64
|
+
|
|
65
|
+
If you want to enable JobTick in a non-production environment (e.g. to test your setup on staging before going live), opt in explicitly:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
# config/initializers/jobtick.rb
|
|
69
|
+
|
|
70
|
+
# Enable on staging only
|
|
71
|
+
JobTick.configure do |config|
|
|
72
|
+
config.api_key = ENV['JOBTICK_API_KEY']
|
|
73
|
+
config.enabled = Rails.env.production? || Rails.env.staging?
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
# Enable everywhere — useful for a quick local smoke-test
|
|
79
|
+
JobTick.configure do |config|
|
|
80
|
+
config.api_key = ENV['JOBTICK_API_KEY']
|
|
81
|
+
config.enabled = true
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
# Drive it from an env var so you can toggle without a deploy
|
|
87
|
+
JobTick.configure do |config|
|
|
88
|
+
config.api_key = ENV['JOBTICK_API_KEY']
|
|
89
|
+
config.enabled = ENV['JOBTICK_ENABLED'] == 'true'
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
61
93
|
### Removing stale monitors automatically
|
|
62
94
|
|
|
63
95
|
By default, monitors are only added — nothing is removed when you delete a job from your schedule. To have each deploy also clean up monitors that are no longer in your config, enable pruning:
|
data/lib/jobtick/client.rb
CHANGED
|
@@ -1,53 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require "json"
|
|
5
|
-
require "uri"
|
|
3
|
+
require_relative "dispatcher"
|
|
6
4
|
|
|
7
5
|
module JobTick
|
|
8
6
|
class Client
|
|
9
|
-
|
|
7
|
+
PING_PREFIX = "/ping/"
|
|
8
|
+
SYNC_PATH = "/monitors/sync"
|
|
10
9
|
|
|
11
10
|
def ping(monitor_key, status:, duration: nil, message: nil)
|
|
12
|
-
|
|
13
|
-
return
|
|
11
|
+
config = JobTick.config
|
|
12
|
+
return unless config.enabled && !config.api_key.nil?
|
|
14
13
|
|
|
15
14
|
payload = { status: status }
|
|
16
15
|
payload[:duration] = duration.round(3) if duration
|
|
17
16
|
payload[:message] = message if message
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
Dispatcher.enqueue("#{PING_PREFIX}#{monitor_key}", payload)
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
def register(monitors, app_name: nil, prune: false)
|
|
23
|
-
|
|
24
|
-
return
|
|
22
|
+
config = JobTick.config
|
|
23
|
+
return unless config.enabled && !config.api_key.nil?
|
|
25
24
|
|
|
26
25
|
payload = { monitors: monitors }
|
|
27
26
|
payload[:app_name] = app_name if app_name && !app_name.empty?
|
|
28
27
|
payload[:prune] = true if prune
|
|
29
|
-
post("/monitors/sync", payload)
|
|
30
|
-
end
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def post(path, body)
|
|
35
|
-
uri = URI("#{JobTick.config.endpoint}#{path}")
|
|
36
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
37
|
-
http.use_ssl = uri.scheme == "https"
|
|
38
|
-
http.open_timeout = TIMEOUT
|
|
39
|
-
http.read_timeout = TIMEOUT
|
|
40
|
-
|
|
41
|
-
request = Net::HTTP::Post.new(uri)
|
|
42
|
-
request["Content-Type"] = "application/json"
|
|
43
|
-
request["Authorization"] = "Bearer #{JobTick.config.api_key}"
|
|
44
|
-
request["User-Agent"] = "jobtick-ruby/#{JobTick::VERSION}"
|
|
45
|
-
request.body = body.to_json
|
|
46
|
-
|
|
47
|
-
http.request(request)
|
|
48
|
-
rescue StandardError => e
|
|
49
|
-
JobTick.logger.warn("[JobTick] HTTP request failed (#{path}): #{e.message}")
|
|
50
|
-
nil
|
|
29
|
+
Dispatcher.send_sync(SYNC_PATH, payload)
|
|
51
30
|
end
|
|
52
31
|
end
|
|
53
32
|
end
|
|
@@ -2,13 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
module JobTick
|
|
4
4
|
class Configuration
|
|
5
|
-
|
|
5
|
+
DEFAULT_QUEUE_LIMIT = 1000
|
|
6
|
+
|
|
7
|
+
attr_accessor :api_key, :endpoint, :environment, :enabled, :prune, :queue_limit
|
|
6
8
|
|
|
7
9
|
def initialize
|
|
8
10
|
@endpoint = "https://api.jobtick.app/v1"
|
|
9
11
|
@environment = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "production"
|
|
10
12
|
@enabled = @environment == "production"
|
|
11
13
|
@prune = false
|
|
14
|
+
@queue_limit = DEFAULT_QUEUE_LIMIT
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def enabled?
|
|
18
|
+
@enabled && !@api_key.nil?
|
|
12
19
|
end
|
|
13
20
|
end
|
|
14
21
|
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "uri"
|
|
6
|
+
require "openssl"
|
|
7
|
+
|
|
8
|
+
module JobTick
|
|
9
|
+
# Asynchronous, single-threaded HTTP dispatcher with a persistent keep-alive
|
|
10
|
+
# connection. Job threads call .enqueue and return immediately; the dispatcher
|
|
11
|
+
# daemon thread drains the queue and posts to the JobTick API.
|
|
12
|
+
#
|
|
13
|
+
# All HTTP work (sync register + async pings) shares one Net::HTTP instance
|
|
14
|
+
# serialized by @http_mutex. The connection is reopened lazily after errors.
|
|
15
|
+
module Dispatcher
|
|
16
|
+
SHUTDOWN_SIGNAL = :__shutdown__
|
|
17
|
+
HEADER_CONTENT_TYPE = "application/json"
|
|
18
|
+
USER_AGENT = "jobtick-ruby/#{JobTick::VERSION}".freeze
|
|
19
|
+
OPEN_TIMEOUT = 5
|
|
20
|
+
READ_TIMEOUT = 5
|
|
21
|
+
KEEP_ALIVE_TIMEOUT = 30
|
|
22
|
+
|
|
23
|
+
NETWORK_ERRORS = [
|
|
24
|
+
IOError, EOFError,
|
|
25
|
+
Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ECONNABORTED,
|
|
26
|
+
Errno::EPIPE, Errno::ETIMEDOUT, Errno::EHOSTUNREACH,
|
|
27
|
+
Net::OpenTimeout, Net::ReadTimeout,
|
|
28
|
+
OpenSSL::SSL::SSLError, SocketError
|
|
29
|
+
].freeze
|
|
30
|
+
|
|
31
|
+
class << self
|
|
32
|
+
attr_accessor :synchronous
|
|
33
|
+
|
|
34
|
+
def enqueue(path, payload)
|
|
35
|
+
return send_request(path, payload) if @synchronous
|
|
36
|
+
|
|
37
|
+
ensure_started
|
|
38
|
+
@queue.push([path, payload], true)
|
|
39
|
+
nil
|
|
40
|
+
rescue ThreadError
|
|
41
|
+
@dropped += 1
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def send_sync(path, payload)
|
|
46
|
+
send_request(path, payload)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def flush(timeout: 5)
|
|
50
|
+
return unless @running && @queue
|
|
51
|
+
|
|
52
|
+
deadline = monotonic + timeout
|
|
53
|
+
until @queue.empty? && @inflight.zero?
|
|
54
|
+
sleep 0.001
|
|
55
|
+
break if monotonic > deadline
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def shutdown(timeout: 2)
|
|
60
|
+
return unless @running
|
|
61
|
+
|
|
62
|
+
@running = false
|
|
63
|
+
@queue&.push(SHUTDOWN_SIGNAL)
|
|
64
|
+
@thread&.join(timeout)
|
|
65
|
+
close_http
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def dropped
|
|
70
|
+
@dropped || 0
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def reset!
|
|
74
|
+
shutdown(timeout: 1) if @running
|
|
75
|
+
@queue = nil
|
|
76
|
+
@thread = nil
|
|
77
|
+
@dropped = 0
|
|
78
|
+
@inflight = 0
|
|
79
|
+
@endpoint_uri = nil
|
|
80
|
+
@at_exit_registered = false
|
|
81
|
+
@synchronous = false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def ensure_started
|
|
87
|
+
return if @running
|
|
88
|
+
|
|
89
|
+
boot_mutex.synchronize do
|
|
90
|
+
return if @running
|
|
91
|
+
|
|
92
|
+
@queue = SizedQueue.new(queue_limit)
|
|
93
|
+
@dropped = 0
|
|
94
|
+
@inflight = 0
|
|
95
|
+
@thread = Thread.new { run_loop }
|
|
96
|
+
@thread.name = "jobtick-dispatcher" if @thread.respond_to?(:name=)
|
|
97
|
+
@running = true
|
|
98
|
+
register_at_exit
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def boot_mutex
|
|
103
|
+
@boot_mutex ||= Mutex.new
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def http_mutex
|
|
107
|
+
@http_mutex ||= Mutex.new
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def queue_limit
|
|
111
|
+
JobTick.config.queue_limit || Configuration::DEFAULT_QUEUE_LIMIT
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def register_at_exit
|
|
115
|
+
return if @at_exit_registered
|
|
116
|
+
|
|
117
|
+
@at_exit_registered = true
|
|
118
|
+
at_exit { shutdown }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def run_loop
|
|
122
|
+
while (item = @queue.pop)
|
|
123
|
+
break if item == SHUTDOWN_SIGNAL
|
|
124
|
+
|
|
125
|
+
@inflight = 1
|
|
126
|
+
path, payload = item
|
|
127
|
+
send_request(path, payload)
|
|
128
|
+
@inflight = 0
|
|
129
|
+
end
|
|
130
|
+
rescue StandardError => e
|
|
131
|
+
JobTick.logger.warn("[JobTick] Dispatcher thread crashed: #{e.message}")
|
|
132
|
+
ensure
|
|
133
|
+
close_http
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def send_request(path, payload)
|
|
137
|
+
body = JSON.generate(payload)
|
|
138
|
+
full_path = "#{endpoint_uri.path}#{path}"
|
|
139
|
+
http_mutex.synchronize do
|
|
140
|
+
http = http_connection
|
|
141
|
+
request = Net::HTTP::Post.new(full_path)
|
|
142
|
+
request["Content-Type"] = HEADER_CONTENT_TYPE
|
|
143
|
+
request["Authorization"] = "Bearer #{JobTick.config.api_key}"
|
|
144
|
+
request["User-Agent"] = USER_AGENT
|
|
145
|
+
request.body = body
|
|
146
|
+
http.request(request)
|
|
147
|
+
end
|
|
148
|
+
rescue *NETWORK_ERRORS => e
|
|
149
|
+
JobTick.logger.warn("[JobTick] HTTP request failed (#{path}): #{e.message}")
|
|
150
|
+
teardown_http
|
|
151
|
+
nil
|
|
152
|
+
rescue StandardError => e
|
|
153
|
+
JobTick.logger.warn("[JobTick] HTTP request failed (#{path}): #{e.message}")
|
|
154
|
+
nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def endpoint_uri
|
|
158
|
+
@endpoint_uri ||= URI(JobTick.config.endpoint)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def http_connection
|
|
162
|
+
return @http if @http&.started?
|
|
163
|
+
|
|
164
|
+
uri = endpoint_uri
|
|
165
|
+
@http = Net::HTTP.new(uri.host, uri.port)
|
|
166
|
+
@http.use_ssl = uri.scheme == "https"
|
|
167
|
+
@http.open_timeout = OPEN_TIMEOUT
|
|
168
|
+
@http.read_timeout = READ_TIMEOUT
|
|
169
|
+
@http.keep_alive_timeout = KEEP_ALIVE_TIMEOUT
|
|
170
|
+
@http.start
|
|
171
|
+
@http
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def teardown_http
|
|
175
|
+
return unless @http
|
|
176
|
+
|
|
177
|
+
@http.finish if @http.started?
|
|
178
|
+
rescue StandardError
|
|
179
|
+
nil
|
|
180
|
+
ensure
|
|
181
|
+
@http = nil
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def close_http
|
|
185
|
+
http_mutex.synchronize { teardown_http }
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def monotonic
|
|
189
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
data/lib/jobtick/monitor.rb
CHANGED
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module JobTick
|
|
4
4
|
class Monitor
|
|
5
|
+
MONOTONIC = Process::CLOCK_MONOTONIC
|
|
6
|
+
|
|
5
7
|
def self.run(key)
|
|
6
|
-
|
|
8
|
+
config = JobTick.config
|
|
9
|
+
return yield unless config.enabled && !config.api_key.nil?
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
client = JobTick.client
|
|
12
|
+
client.ping(key, status: :started)
|
|
13
|
+
started = Process.clock_gettime(MONOTONIC)
|
|
14
|
+
result = yield
|
|
15
|
+
duration = Process.clock_gettime(MONOTONIC) - started
|
|
16
|
+
client.ping(key, status: :completed, duration: duration)
|
|
13
17
|
result
|
|
14
18
|
rescue StandardError => e
|
|
15
19
|
JobTick.client.ping(key, status: :failed, message: e.message)
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module JobTick
|
|
4
4
|
module Parsers
|
|
5
|
+
SLUG_RE = /[^a-z0-9]+/
|
|
6
|
+
SLUG_TRIM_RE = /\A_+|_+\z/
|
|
7
|
+
|
|
5
8
|
def self.slugify(str)
|
|
6
|
-
str.downcase.gsub(
|
|
9
|
+
str.downcase.gsub(SLUG_RE, "_").gsub(SLUG_TRIM_RE, "")
|
|
7
10
|
end
|
|
8
11
|
|
|
9
12
|
class Sidekiq
|
|
@@ -16,16 +16,16 @@ module JobTick
|
|
|
16
16
|
tasks = yaml[env] || yaml["default"] || yaml
|
|
17
17
|
return [] unless tasks.is_a?(Hash)
|
|
18
18
|
|
|
19
|
-
tasks.
|
|
19
|
+
tasks.each_with_object([]) do |(key, config), out|
|
|
20
20
|
next unless config.is_a?(Hash)
|
|
21
21
|
|
|
22
|
-
{
|
|
22
|
+
out << {
|
|
23
23
|
key: "solid_queue.#{key}",
|
|
24
24
|
schedule: config["schedule"],
|
|
25
25
|
source: "solid_queue",
|
|
26
26
|
task: config["class"]
|
|
27
27
|
}
|
|
28
|
-
end
|
|
28
|
+
end
|
|
29
29
|
rescue StandardError => e
|
|
30
30
|
JobTick.logger.warn("[JobTick] Solid Queue parser failed: #{e.message}")
|
|
31
31
|
[]
|
data/lib/jobtick/railtie.rb
CHANGED
|
@@ -6,6 +6,13 @@ module JobTick
|
|
|
6
6
|
ActiveSupport.on_load(:after_initialize) do
|
|
7
7
|
next unless JobTick.config.enabled
|
|
8
8
|
|
|
9
|
+
require_relative "parsers/whenever"
|
|
10
|
+
require_relative "parsers/solid_queue"
|
|
11
|
+
require_relative "parsers/sidekiq"
|
|
12
|
+
require_relative "registry"
|
|
13
|
+
require_relative "hooks/active_job"
|
|
14
|
+
require_relative "middleware/sidekiq"
|
|
15
|
+
|
|
9
16
|
JobTick::Registry.sync
|
|
10
17
|
|
|
11
18
|
::ActiveJob::Base.include(JobTick::Hooks::ActiveJob) if defined?(::ActiveJob::Base)
|
data/lib/jobtick/registry.rb
CHANGED
|
@@ -9,9 +9,9 @@ module JobTick
|
|
|
9
9
|
Parsers::Sidekiq.parse
|
|
10
10
|
].flatten.compact
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
map = {}
|
|
13
|
+
monitors.each { |m| map[m[:task]] = m[:key] if m[:task] }
|
|
14
|
+
JobTick.monitor_map = map.freeze
|
|
15
15
|
|
|
16
16
|
return [] if monitors.empty?
|
|
17
17
|
|
data/lib/jobtick/version.rb
CHANGED
data/lib/jobtick.rb
CHANGED
|
@@ -5,15 +5,11 @@ require_relative "jobtick/version"
|
|
|
5
5
|
require_relative "jobtick/configuration"
|
|
6
6
|
require_relative "jobtick/client"
|
|
7
7
|
require_relative "jobtick/monitor"
|
|
8
|
-
require_relative "jobtick/parsers/whenever"
|
|
9
|
-
require_relative "jobtick/parsers/solid_queue"
|
|
10
|
-
require_relative "jobtick/parsers/sidekiq"
|
|
11
|
-
require_relative "jobtick/registry"
|
|
12
|
-
require_relative "jobtick/hooks/active_job"
|
|
13
|
-
require_relative "jobtick/middleware/sidekiq"
|
|
14
8
|
require_relative "jobtick/railtie" if defined?(Rails::Railtie)
|
|
15
9
|
|
|
16
10
|
module JobTick
|
|
11
|
+
EMPTY_MAP = {}.freeze
|
|
12
|
+
|
|
17
13
|
class Error < StandardError; end
|
|
18
14
|
|
|
19
15
|
class << self
|
|
@@ -34,7 +30,7 @@ module JobTick
|
|
|
34
30
|
end
|
|
35
31
|
|
|
36
32
|
def monitor_map
|
|
37
|
-
@monitor_map ||=
|
|
33
|
+
@monitor_map ||= EMPTY_MAP
|
|
38
34
|
end
|
|
39
35
|
|
|
40
36
|
attr_writer :monitor_map
|
|
@@ -44,9 +40,10 @@ module JobTick
|
|
|
44
40
|
end
|
|
45
41
|
|
|
46
42
|
def reset!
|
|
43
|
+
Dispatcher.reset! if defined?(Dispatcher)
|
|
47
44
|
@config = nil
|
|
48
45
|
@client = nil
|
|
49
|
-
@monitor_map =
|
|
46
|
+
@monitor_map = EMPTY_MAP
|
|
50
47
|
end
|
|
51
48
|
end
|
|
52
49
|
end
|
data/lib/tasks/jobtick.rake
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
namespace :jobtick do
|
|
4
4
|
desc "Sync discovered jobs with jobtick.app"
|
|
5
5
|
task sync: :environment do
|
|
6
|
+
require "jobtick/parsers/whenever"
|
|
7
|
+
require "jobtick/parsers/solid_queue"
|
|
8
|
+
require "jobtick/parsers/sidekiq"
|
|
9
|
+
require "jobtick/registry"
|
|
10
|
+
|
|
6
11
|
monitors = JobTick::Registry.sync
|
|
7
12
|
count = monitors&.length || 0
|
|
8
13
|
puts "[JobTick] Synced #{count} monitor(s)"
|
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.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Clearstack Labs
|
|
@@ -38,6 +38,7 @@ files:
|
|
|
38
38
|
- lib/jobtick.rb
|
|
39
39
|
- lib/jobtick/client.rb
|
|
40
40
|
- lib/jobtick/configuration.rb
|
|
41
|
+
- lib/jobtick/dispatcher.rb
|
|
41
42
|
- lib/jobtick/hooks/active_job.rb
|
|
42
43
|
- lib/jobtick/middleware/sidekiq.rb
|
|
43
44
|
- lib/jobtick/monitor.rb
|