active_job_tracker 0.1.0 → 0.3.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/README.md +32 -6
- data/app/models/active_job_tracker_record.rb +21 -4
- data/app/views/active_job_tracker/_active_job_tracker_wrapper.html.erb +1 -1
- data/app/views/active_job_tracker/_radial_progress.html.erb +41 -0
- data/lib/active_job_tracker/configuration.rb +10 -0
- data/lib/active_job_tracker/version.rb +1 -1
- data/lib/active_job_tracker.rb +3 -2
- data/lib/generators/active_job_tracker/templates/config/initializers/active_job_tracker.rb +7 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b8342cf50be46737b9d191b7d631008c6cecad77fc81d1e0fcfca23c4ff6007
|
4
|
+
data.tar.gz: 02a1d61e46c41f6241b8be9d25ba311c42f882b1db71e94afc7d19062bbe3e31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b46f5815fd0809154e222e50e388f6aa49bde11cb904d12bb8ff12fe9ecf1ccf2f41b0e250620b09accf18f0755e3e275b997380ee9284d9b1e290f6b2ead6b
|
7
|
+
data.tar.gz: f60e1e47250e60af0693f3a9f81cfcc8777289b2640e1a0b8f96b2b29bd3d61f9e42624148169fc2ba3b32ef186ee2e9c3c75f43784368020c36444b35d1f0e9
|
data/README.md
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
❤️ I'm looking for a full-time position. Please consider hiring me.
|
2
|
+
|
1
3
|
# ActiveJobTracker
|
2
4
|
|
3
5
|
ActiveJobTracker provides persisted, real-time tracking and monitoring of ActiveJob jobs in Ruby on Rails applications. It allows you to track job status, progress, and errors with a simple API and real-time UI updates via ActionCable.
|
4
6
|
|
5
|
-
<
|
7
|
+
<div align="center">
|
8
|
+
<img width="500" alt="Screenshot 2025-03-04 at 1 09 38 PM" src="https://github.com/user-attachments/assets/d34e6fb8-bb3c-4d71-a737-2f7597a23c43" />
|
9
|
+
</div>
|
6
10
|
|
7
11
|
## Features
|
8
12
|
|
@@ -10,7 +14,7 @@ ActiveJobTracker provides persisted, real-time tracking and monitoring of Active
|
|
10
14
|
- Monitor job progress with percentage completion
|
11
15
|
- Real-time UI updates via ActionCable
|
12
16
|
- Error tracking and reporting
|
13
|
-
- Efficient progress caching to minimize database updates
|
17
|
+
- Efficient progress write-behind caching to minimize database updates
|
14
18
|
- Configurable options
|
15
19
|
|
16
20
|
## Installation
|
@@ -59,6 +63,9 @@ ActiveJobTracker.configure do |config|
|
|
59
63
|
# When true, job updates are automatically broadcast via ActionCable
|
60
64
|
config.auto_broadcast = true
|
61
65
|
|
66
|
+
# Whether to raise an error when progress increments the current value beyond the target value (default: false)
|
67
|
+
config.raise_error_when_target_exceeded = false
|
68
|
+
|
62
69
|
# Default partial path for rendering job trackers
|
63
70
|
# (default: 'active_job_tracker/active_job_tracker')
|
64
71
|
config.default_partial = 'active_job_tracker/active_job_tracker'
|
@@ -66,6 +73,10 @@ ActiveJobTracker.configure do |config|
|
|
66
73
|
# Whether to include the style in the job tracker (default: true)
|
67
74
|
# When true, the gem's CSS styles are automatically included
|
68
75
|
config.include_style = true
|
76
|
+
|
77
|
+
# Custom Turbo Stream channel name (default: 'active_job_tracker')
|
78
|
+
# Use this to customize the ActionCable channel name for real-time updates
|
79
|
+
config.turbo_stream_channel = 'Turbo::StreamsChannel'
|
69
80
|
end
|
70
81
|
```
|
71
82
|
|
@@ -80,9 +91,9 @@ class CsvUpload < ApplicationRecord
|
|
80
91
|
# Sets up polymorphic association to tie this record to the ActiveJobTracker
|
81
92
|
has_one :job, as: :active_job_trackable, class_name: 'ActiveJobTrackerRecord'
|
82
93
|
|
83
|
-
after_create :
|
94
|
+
after_create :process_import
|
84
95
|
|
85
|
-
def
|
96
|
+
def process_import
|
86
97
|
# The tracked record must be passed into the job as the first argument
|
87
98
|
ProcessImportJob.perform_later(self)
|
88
99
|
end
|
@@ -122,13 +133,27 @@ class ProcessImportJob < ApplicationJob
|
|
122
133
|
records.each do |record|
|
123
134
|
# Process item
|
124
135
|
|
125
|
-
# Update progress (increments by 1)
|
136
|
+
# Update progress (increments by 1 by default)
|
126
137
|
active_job_tracker_progress
|
127
138
|
end
|
128
139
|
end
|
129
140
|
end
|
130
141
|
```
|
131
142
|
|
143
|
+
Optionally, you can use a custom value to increment your progress by:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
def perform
|
147
|
+
# Default target is 100
|
148
|
+
|
149
|
+
10.times do
|
150
|
+
# Process item
|
151
|
+
|
152
|
+
active_job_tracker_progress(increment_by: 10)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
132
157
|
For more efficient progress tracking with many updates, use threadsafe progress caching:
|
133
158
|
|
134
159
|
```ruby
|
@@ -167,6 +192,7 @@ This will render a default tracker UI with progress bar, status badge, and job i
|
|
167
192
|
#### Custom Rendering
|
168
193
|
|
169
194
|
You can customize the tracker UI by creating your own partials and using the ActiveJobTrackerRecord model attributes:
|
195
|
+
|
170
196
|
- Make sure to set the `config.default_partial` to the new partial path
|
171
197
|
- Each job block needs to be wrapped with `id="active_job_tracker_<%= tracker.id %>"` for turbo to update your frontend
|
172
198
|
|
@@ -260,7 +286,7 @@ end
|
|
260
286
|
|
261
287
|
## Development
|
262
288
|
|
263
|
-
After checking out the repo, run `
|
289
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rails test` to run the tests.
|
264
290
|
|
265
291
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
266
292
|
|
@@ -43,14 +43,15 @@ class ActiveJobTrackerRecord < ApplicationRecord
|
|
43
43
|
[ current.to_f / target.to_f, 1.0 ].min
|
44
44
|
end
|
45
45
|
|
46
|
-
def progress(use_cache
|
46
|
+
def progress(use_cache: true, increment_by: 1)
|
47
47
|
if use_cache
|
48
48
|
key = progress_cache_key
|
49
49
|
should_flush = false
|
50
50
|
|
51
51
|
@@mutex.synchronize do
|
52
52
|
current_value = Rails.cache.fetch(key, expires_in: 1.week) { 0 }.to_i
|
53
|
-
new_value = current_value
|
53
|
+
new_value = incremented_value(current_value: current_value, increment_by: increment_by)
|
54
|
+
|
54
55
|
Rails.cache.write(key, new_value, expires_in: 1.week)
|
55
56
|
|
56
57
|
should_flush = new_value >= self.cache_threshold
|
@@ -60,7 +61,7 @@ class ActiveJobTrackerRecord < ApplicationRecord
|
|
60
61
|
flush_progress_cache if should_flush
|
61
62
|
else
|
62
63
|
with_lock do
|
63
|
-
self.current
|
64
|
+
self.current = incremented_value(current_value: current, increment_by: increment_by)
|
64
65
|
save!
|
65
66
|
end
|
66
67
|
end
|
@@ -86,8 +87,24 @@ class ActiveJobTrackerRecord < ApplicationRecord
|
|
86
87
|
|
87
88
|
private
|
88
89
|
|
90
|
+
def incremented_value(current_value:, increment_by:)
|
91
|
+
new_value = current_value + increment_by
|
92
|
+
|
93
|
+
if new_value > target
|
94
|
+
if ActiveJobTracker.configuration.raise_error_when_target_exceeded
|
95
|
+
raise ActiveJobTracker::Error::TargetExceeded.new(
|
96
|
+
"The current value of #{new_value} exceeds the target value of #{target}"
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
target
|
101
|
+
else
|
102
|
+
new_value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
89
106
|
def broadcast_changes
|
90
|
-
broadcast_replace_to(
|
107
|
+
ActiveJobTracker.configuration.turbo_stream_channel.constantize.broadcast_replace_to(
|
91
108
|
"active_job_trackers",
|
92
109
|
target: "active_job_tracker_#{self.id}",
|
93
110
|
partial: ActiveJobTracker.configuration.default_partial,
|
@@ -6,7 +6,7 @@
|
|
6
6
|
html_options ||= {}
|
7
7
|
css_class = html_options[:class] || "active_job_tracker-container"
|
8
8
|
%>
|
9
|
-
<%= turbo_stream_from "active_job_trackers" %>
|
9
|
+
<%= turbo_stream_from "active_job_trackers", channel: ActiveJobTracker.configuration.turbo_stream_channel %>
|
10
10
|
<div class="<%= css_class %>" data-controller="active_job_tracker-container">
|
11
11
|
<%= content %>
|
12
12
|
</div>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<%
|
2
|
+
percentage = active_job_tracker_record.progress_percentage
|
3
|
+
status = active_job_tracker_record.status
|
4
|
+
|
5
|
+
# Calculate the stroke-dasharray and stroke-dashoffset for the circle
|
6
|
+
circumference = 2 * Math::PI * 45 # 45 is the radius of the circle
|
7
|
+
stroke_dashoffset = circumference * (1 - percentage / 100.0)
|
8
|
+
%>
|
9
|
+
|
10
|
+
<div class="active_job_tracker-radial-progress">
|
11
|
+
<svg width="100" height="100" viewBox="0 0 100 100">
|
12
|
+
<circle
|
13
|
+
class="active_job_tracker-radial-progress-bg"
|
14
|
+
cx="50"
|
15
|
+
cy="50"
|
16
|
+
r="45"
|
17
|
+
fill="none"
|
18
|
+
stroke-width="8"
|
19
|
+
/>
|
20
|
+
<circle
|
21
|
+
class="active_job_tracker-radial-progress-fill active_job_tracker-radial-progress-<%= status %>"
|
22
|
+
cx="50"
|
23
|
+
cy="50"
|
24
|
+
r="45"
|
25
|
+
fill="none"
|
26
|
+
stroke-width="8"
|
27
|
+
stroke-dasharray="<%= circumference %>"
|
28
|
+
stroke-dashoffset="<%= stroke_dashoffset %>"
|
29
|
+
transform="rotate(-90 50 50)"
|
30
|
+
/>
|
31
|
+
<text
|
32
|
+
class="active_job_tracker-radial-progress-text"
|
33
|
+
x="50"
|
34
|
+
y="50"
|
35
|
+
text-anchor="middle"
|
36
|
+
dominant-baseline="middle"
|
37
|
+
>
|
38
|
+
<%= percentage %>%
|
39
|
+
</text>
|
40
|
+
</svg>
|
41
|
+
</div>
|
@@ -19,17 +19,27 @@ module ActiveJobTracker
|
|
19
19
|
# @return [String]
|
20
20
|
attr_accessor :default_partial
|
21
21
|
|
22
|
+
# Whether to raise an error when progress increments the current value beyond the target value
|
23
|
+
# @return [Boolean]
|
24
|
+
attr_accessor :raise_error_when_target_exceeded
|
25
|
+
|
22
26
|
# Whether to include the style in the job tracker
|
23
27
|
# @return [Boolean]
|
24
28
|
attr_accessor :include_style
|
25
29
|
|
30
|
+
# The turbo stream channel to use for broadcasting job tracker updates
|
31
|
+
# @return [String]
|
32
|
+
attr_accessor :turbo_stream_channel
|
33
|
+
|
26
34
|
# Initialize with default values
|
27
35
|
def initialize
|
28
36
|
@default_target = 100
|
29
37
|
@cache_threshold = 10
|
30
38
|
@auto_broadcast = true
|
39
|
+
@raise_error_when_target_exceeded = false
|
31
40
|
@default_partial = "active_job_tracker/active_job_tracker"
|
32
41
|
@include_style = true
|
42
|
+
@turbo_stream_channel = "Turbo::StreamsChannel"
|
33
43
|
end
|
34
44
|
end
|
35
45
|
end
|
data/lib/active_job_tracker.rb
CHANGED
@@ -6,6 +6,7 @@ module ActiveJobTracker
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
class Error < StandardError
|
9
|
+
class TargetExceeded < Error; end
|
9
10
|
end
|
10
11
|
|
11
12
|
def self.configuration
|
@@ -35,8 +36,8 @@ module ActiveJobTracker
|
|
35
36
|
active_job_tracker.update(target: target)
|
36
37
|
end
|
37
38
|
|
38
|
-
def active_job_tracker_progress(cache: false)
|
39
|
-
active_job_tracker.progress(cache)
|
39
|
+
def active_job_tracker_progress(cache: false, increment_by: 1)
|
40
|
+
active_job_tracker.progress(use_cache: cache, increment_by: increment_by)
|
40
41
|
end
|
41
42
|
|
42
43
|
def active_job_tracker
|
@@ -15,6 +15,9 @@ ActiveJobTracker.configure do |config|
|
|
15
15
|
# When true, job updates are automatically broadcast via ActionCable
|
16
16
|
config.auto_broadcast = true
|
17
17
|
|
18
|
+
# Whether to raise an error when progress increments the current value beyond the target value
|
19
|
+
config.raise_error_when_target_exceeded = false
|
20
|
+
|
18
21
|
# Default partial path for rendering job trackers
|
19
22
|
# (default: 'active_job_tracker/shared/active_job_tracker')
|
20
23
|
config.default_partial = "active_job_tracker/active_job_tracker"
|
@@ -22,4 +25,8 @@ ActiveJobTracker.configure do |config|
|
|
22
25
|
# Whether to include the style in the job tracker (default: true)
|
23
26
|
# When true, the gem's CSS styles are automatically included
|
24
27
|
config.include_style = true
|
28
|
+
|
29
|
+
# The turbo stream channel to use for broadcasting job tracker updates
|
30
|
+
# (default: 'Turbo::StreamsChannel')
|
31
|
+
config.turbo_stream_channel = "Turbo::StreamsChannel"
|
25
32
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_job_tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Seena Sabti
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-10 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rails
|
@@ -23,6 +23,20 @@ dependencies:
|
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: 8.0.1
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: turbo-rails
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.0.11
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 2.0.11
|
26
40
|
- !ruby/object:Gem::Dependency
|
27
41
|
name: mocha
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -120,6 +134,7 @@ files:
|
|
120
134
|
- app/models/active_job_tracker_record.rb
|
121
135
|
- app/views/active_job_tracker/_active_job_tracker.html.erb
|
122
136
|
- app/views/active_job_tracker/_active_job_tracker_wrapper.html.erb
|
137
|
+
- app/views/active_job_tracker/_radial_progress.html.erb
|
123
138
|
- lib/active_job_tracker.rb
|
124
139
|
- lib/active_job_tracker/configuration.rb
|
125
140
|
- lib/active_job_tracker/engine.rb
|