rush_job_mongoid 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +60 -0
- data/Rakefile +5 -0
- data/app/assets/config/rush_job_mongoid_manifest.js +4 -0
- data/app/assets/images/rush_job_mongoid/funnel-fill.svg +3 -0
- data/app/assets/images/rush_job_mongoid/funnel.svg +3 -0
- data/app/assets/images/rush_job_mongoid/pencil-square-dark.svg +4 -0
- data/app/assets/images/rush_job_mongoid/pencil-square-light.svg +4 -0
- data/app/assets/javascript/rush_job_mongoid/application.js +13 -0
- data/app/assets/javascript/rush_job_mongoid/controllers/rush_job_mongoid_filters_controller.js +9 -0
- data/app/assets/javascript/rush_job_mongoid/controllers/rush_job_mongoid_polling_controller.js +50 -0
- data/app/assets/javascript/rush_job_mongoid/controllers/rush_job_mongoid_reload_jobs_table_controller.js +7 -0
- data/app/assets/javascript/rush_job_mongoid/controllers/rush_job_mongoid_table_update_controller.js +19 -0
- data/app/assets/stylesheets/rush_job_mongoid/application.scss +16 -0
- data/app/assets/stylesheets/rush_job_mongoid/components/_polling.scss +3 -0
- data/app/assets/stylesheets/rush_job_mongoid/layout/_container.scss +4 -0
- data/app/controllers/rush_job_mongoid/application_controller.rb +5 -0
- data/app/controllers/rush_job_mongoid/dashboard_controller.rb +28 -0
- data/app/controllers/rush_job_mongoid/rush_jobs_controller.rb +57 -0
- data/app/controllers/rush_job_mongoid/settings_controller.rb +18 -0
- data/app/helpers/rush_job_mongoid/application_helper.rb +6 -0
- data/app/helpers/rush_job_mongoid/filter_helper.rb +20 -0
- data/app/helpers/rush_job_mongoid/settings_helper.rb +19 -0
- data/app/models/rush_job_mongoid/rush_job.rb +83 -0
- data/app/presenters/rush_job_mongoid/pagination_presenter.rb +17 -0
- data/app/presenters/rush_job_mongoid/queue_groups_presenter.rb +25 -0
- data/app/services/rush_job_mongoid/locked_jobs.rb +15 -0
- data/app/services/rush_job_mongoid/settings.rb +19 -0
- data/app/views/layouts/rush_job_mongoid/_filter_modal.html.erb +58 -0
- data/app/views/layouts/rush_job_mongoid/_flash_messages.html.erb +5 -0
- data/app/views/layouts/rush_job_mongoid/_navbar.html.erb +72 -0
- data/app/views/layouts/rush_job_mongoid/application.html.erb +24 -0
- data/app/views/rush_job_mongoid/dashboard/_dashboard_tables.html.erb +34 -0
- data/app/views/rush_job_mongoid/dashboard/_queues_table.html.erb +39 -0
- data/app/views/rush_job_mongoid/dashboard/index.html.erb +7 -0
- data/app/views/rush_job_mongoid/dashboard/index.js.erb +3 -0
- data/app/views/rush_job_mongoid/rush_jobs/_jobs_table.html.erb +43 -0
- data/app/views/rush_job_mongoid/rush_jobs/edit.html.erb +51 -0
- data/app/views/rush_job_mongoid/rush_jobs/index.html.erb +7 -0
- data/app/views/rush_job_mongoid/rush_jobs/index.js.erb +3 -0
- data/app/views/rush_job_mongoid/shared/_pagination.html.erb +89 -0
- data/app/views/rush_job_mongoid/shared/_pagination_link.html.erb +3 -0
- data/app/views/rush_job_mongoid/shared/_polling.html.erb +32 -0
- data/config/importmap.rb +5 -0
- data/config/locales/en.yml +46 -0
- data/config/routes.rb +7 -0
- data/lib/rush_job_mongoid/engine.rb +23 -0
- data/lib/rush_job_mongoid/version.rb +3 -0
- data/lib/rush_job_mongoid.rb +6 -0
- data/lib/tasks/rush_job_mongoid_tasks.rake +4 -0
- data/vendor/stylesheets/rush_job_mongoid/bootstrap.css +12273 -0
- metadata +364 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 965c03dc946e6df0a48d7d174e4cc88554c754ab9348f20568177790d866125b
|
4
|
+
data.tar.gz: db8783bcb66c206c1ad374799595ab58b6f13e97f0b442f2ac1ed4990efc0e01
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 24a160ff6b9a070d8d1267ce6374b5f82ce0114da5fd4f55f59d9ed48889b2f47caf2fe8e38c1383adf86cc90e7a516ee0667dfd18cd917d6cffe9e229a0ef76
|
7
|
+
data.tar.gz: 6191e7b39f8077e2ea636fc047cf7c5db2d89cd285b5f9c86e13b4dfdf27d54f26d0c926c11b75c1de66a9685e9542c23598a2cb25f460f7e1a17943deb866bb
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright JavaKoala
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# RushJobMongoid
|
2
|
+
User interface for Delayed Job Mongoid (https://github.com/collectiveidea/delayed_job_mongoid) in Ruby on Rails
|
3
|
+
|
4
|
+
<img width="656" alt="Dashboard" src="docs/assets/dashboard.png">
|
5
|
+
<img width="656" alt="Jobs" src="docs/assets/jobs.png">
|
6
|
+
|
7
|
+
### Note
|
8
|
+
- This app uses cookies to store the selected options.
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
You will need Delayed Job, `delayed_job`, and Delayed Job Mongoid, `delayed_job_mongoid`, installed in a Ruby on Rails application for this gem to work properly.
|
12
|
+
|
13
|
+
Navigate to the `/rush_job_mongoid` route in your application to see the Delayed Jobs. Locally this would be `http://localhost:3000/rush_job_mongoid`
|
14
|
+
|
15
|
+
### Options
|
16
|
+
|
17
|
+
#### Dark Mode
|
18
|
+
|
19
|
+
Enables or disables dark mode
|
20
|
+
|
21
|
+
#### Editing
|
22
|
+
|
23
|
+
Make sure workers are stopped before editing
|
24
|
+
|
25
|
+
#### Queues
|
26
|
+
|
27
|
+
Queues on the dashboard are eager loaded. If there are lots of queues this can affect performance. Disable queues if this becomes an issue.
|
28
|
+
|
29
|
+
## Installation
|
30
|
+
Add this line to your Ruby on Rails application's Gemfile:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
gem 'rush_job', '~> 1.0.0'
|
34
|
+
```
|
35
|
+
|
36
|
+
And then execute:
|
37
|
+
```bash
|
38
|
+
$ bundle install
|
39
|
+
```
|
40
|
+
|
41
|
+
Add the following to your `config/routes.rb` file:
|
42
|
+
```ruby
|
43
|
+
mount RushJob::Engine => '/rush_job_mongoid'
|
44
|
+
```
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
Open an issue or
|
48
|
+
1. Fork
|
49
|
+
2. Update
|
50
|
+
3. Test
|
51
|
+
1. `bundle exec rails app:test:all` and check coverage in `test/coverage/index.html`
|
52
|
+
2. `bundle exec rubocop`
|
53
|
+
3. `bundle exec brakeman`
|
54
|
+
4. Open pull request
|
55
|
+
|
56
|
+
## Upcoming
|
57
|
+
1. Remove dependency on Rails UJS and move to Hotwire and Turbo
|
58
|
+
|
59
|
+
## License
|
60
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(255, 255, 255)" class="bi bi-funnel-fill" viewBox="0 0 16 16">
|
2
|
+
<path d="M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5z"/>
|
3
|
+
</svg>
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(255, 255, 255)" class="bi bi-funnel" viewBox="0 0 16 16">
|
2
|
+
<path d="M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5zm1 .5v1.308l4.372 4.858A.5.5 0 0 1 7 8.5v5.306l2-.666V8.5a.5.5 0 0 1 .128-.334L13.5 3.308V2z"/>
|
3
|
+
</svg>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(0, 0, 0)" class="bi bi-pencil-square" viewBox="0 0 16 16">
|
2
|
+
<path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
|
3
|
+
<path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5z"/>
|
4
|
+
</svg>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(255, 255, 255)" class="bi bi-pencil-square" viewBox="0 0 16 16">
|
2
|
+
<path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
|
3
|
+
<path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5z"/>
|
4
|
+
</svg>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Application } from '@hotwired/stimulus';
|
2
|
+
import Rails from '@rails/ujs';
|
3
|
+
import RushJobMongoidFiltersController from './controllers/rush_job_mongoid_filters_controller';
|
4
|
+
import RushJobMongoidPollingController from './controllers/rush_job_mongoid_polling_controller';
|
5
|
+
import RushJobMongoidReloadJobsTableController from './controllers/rush_job_mongoid_reload_jobs_table_controller';
|
6
|
+
import 'bootstrap';
|
7
|
+
|
8
|
+
Rails.start();
|
9
|
+
|
10
|
+
window.Stimulus = Application.start();
|
11
|
+
Stimulus.register('rush-job-mongoid-filter', RushJobMongoidFiltersController);
|
12
|
+
Stimulus.register('rush-job-mongoid-polling', RushJobMongoidPollingController);
|
13
|
+
Stimulus.register('rush-job-mongoid-reload-jobs-table', RushJobMongoidReloadJobsTableController);
|
data/app/assets/javascript/rush_job_mongoid/controllers/rush_job_mongoid_polling_controller.js
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import { RushJobMongoidTableUpdateController } from './rush_job_mongoid_table_update_controller';
|
2
|
+
|
3
|
+
let intervalID;
|
4
|
+
|
5
|
+
export default class RushJobMongoidPollingController extends RushJobMongoidTableUpdateController {
|
6
|
+
static targets = ['pollingTime', 'pollingTimeLabel', 'pollingSlide'];
|
7
|
+
|
8
|
+
connect() {
|
9
|
+
this.pollingChange();
|
10
|
+
this.stopPolling();
|
11
|
+
}
|
12
|
+
|
13
|
+
pollingChange() {
|
14
|
+
const pollingLabelRegex = /\d+/;
|
15
|
+
const pollingTimeTargetHtml = this.pollingTimeLabelTarget.innerHTML;
|
16
|
+
const pollingLabelUpdate = pollingTimeTargetHtml.replace(pollingLabelRegex, this.pollingTime());
|
17
|
+
this.pollingTimeLabelTarget.innerHTML = pollingLabelUpdate;
|
18
|
+
}
|
19
|
+
|
20
|
+
pollingToggle() {
|
21
|
+
const pollingSlide = this.pollingSlideTarget;
|
22
|
+
|
23
|
+
if (pollingSlide.checked === true) {
|
24
|
+
this.startPolling();
|
25
|
+
} else {
|
26
|
+
this.stopPolling();
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
startPolling() {
|
31
|
+
this.updateJobs();
|
32
|
+
|
33
|
+
intervalID = setTimeout(() => {
|
34
|
+
this.startPolling();
|
35
|
+
}, this.pollingTime() * 1000);
|
36
|
+
}
|
37
|
+
|
38
|
+
stopPolling() {
|
39
|
+
if (intervalID) {
|
40
|
+
clearInterval(intervalID);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
pollingTime() {
|
45
|
+
const pollingTimes = [3, 5, 8, 13, 21, 34, 55];
|
46
|
+
const pollingTime = this.pollingTimeTarget.value || 3;
|
47
|
+
|
48
|
+
return pollingTimes[pollingTime];
|
49
|
+
}
|
50
|
+
}
|
data/app/assets/javascript/rush_job_mongoid/controllers/rush_job_mongoid_table_update_controller.js
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus';
|
2
|
+
import Rails from '@rails/ujs';
|
3
|
+
|
4
|
+
export class RushJobMongoidTableUpdateController extends Controller {
|
5
|
+
updateJobs() {
|
6
|
+
this.blurTable();
|
7
|
+
|
8
|
+
Rails.ajax({
|
9
|
+
url: document.location.href,
|
10
|
+
type: 'GET',
|
11
|
+
dataType: 'script',
|
12
|
+
});
|
13
|
+
}
|
14
|
+
|
15
|
+
blurTable() {
|
16
|
+
const jobsContainer = document.getElementById('rush-job-mongoid-jobs');
|
17
|
+
jobsContainer.classList.add('table-refresh');
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*/
|
14
|
+
@import "../../../vendor/stylesheets/rush_job_mongoid/bootstrap";
|
15
|
+
@import "layout/container";
|
16
|
+
@import "components/polling";
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class DashboardController < ApplicationController
|
3
|
+
include RushJobMongoid::SettingsHelper
|
4
|
+
|
5
|
+
def index
|
6
|
+
@locked_jobs_presenter = PaginationPresenter.new(params[:locked_jobs_page])
|
7
|
+
@locked_jobs = LockedJobs.new(filter_params)
|
8
|
+
@queues_presenter = QueueGroupsPresenter.new(params[:queue_groups_page]) if queue_groups_enabled?
|
9
|
+
end
|
10
|
+
|
11
|
+
def destroy
|
12
|
+
RushJob.clear_queue(queue_params[:queue], queue_params[:priority])
|
13
|
+
|
14
|
+
flash[:success] = t(:cleared_queue, queue: params[:queue])
|
15
|
+
redirect_to root_path, status: :see_other
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def queue_params
|
21
|
+
params.permit(:queue, :priority)
|
22
|
+
end
|
23
|
+
|
24
|
+
def filter_params
|
25
|
+
params.permit(:doc_id, :priority, :attempts, :job_class, :arguments, :locked_by, :last_error, :queue)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class RushJobsController < ApplicationController
|
3
|
+
before_action :find_job, only: %i[edit update destroy]
|
4
|
+
|
5
|
+
def index
|
6
|
+
@pagination_presenter = PaginationPresenter.new(params[:page])
|
7
|
+
@rush_jobs = RushJob.filter(filter_params).locked_by_desc.paginate(@pagination_presenter.page, 20)
|
8
|
+
end
|
9
|
+
|
10
|
+
def edit
|
11
|
+
flash.now[:warning] = t(:edit_warning)
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
if @job.update(update_params)
|
16
|
+
flash[:success] = t(:updated_job, job_id: @job.id)
|
17
|
+
redirect_to rush_jobs_path(doc_id: @job.id)
|
18
|
+
else
|
19
|
+
flash[:danger] = t(:unable_to_update, errors: @job.errors.full_messages.to_sentence)
|
20
|
+
render :edit, status: :unprocessable_entity
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
@job.destroy
|
26
|
+
|
27
|
+
flash[:success] = t(:deleted_job, job_id: @job.id)
|
28
|
+
redirect_to rush_jobs_path
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def find_job
|
34
|
+
@job = RushJob.find(params[:id])
|
35
|
+
rescue Mongoid::Errors::DocumentNotFound => e
|
36
|
+
Rails.logger.info e.message
|
37
|
+
flash[:danger] = t(:missing_document)
|
38
|
+
redirect_to rush_jobs_path
|
39
|
+
end
|
40
|
+
|
41
|
+
def filter_params
|
42
|
+
params.permit(:doc_id, :priority, :attempts, :job_class, :arguments, :locked_by, :last_error, :queue)
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_params
|
46
|
+
params.require(:rush_job).permit(:priority,
|
47
|
+
:attempts,
|
48
|
+
:handler,
|
49
|
+
:run_at,
|
50
|
+
:locked_at,
|
51
|
+
:locked_by,
|
52
|
+
:failed_at,
|
53
|
+
:last_error,
|
54
|
+
:queue)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class SettingsController < ApplicationController
|
3
|
+
def update
|
4
|
+
change_setting if Settings::RUSH_JOB_SETTINGS[params[:setting]&.to_sym]
|
5
|
+
|
6
|
+
redirect_to root_path
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def change_setting
|
12
|
+
setting_param = params[:setting]
|
13
|
+
setting_cookie = "rush_job_#{setting_param}"
|
14
|
+
|
15
|
+
cookies.permanent[setting_cookie.to_sym] = Settings.change_setting(setting_param, cookies[setting_cookie.to_sym])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
module FilterHelper
|
3
|
+
def filter_param_query
|
4
|
+
{
|
5
|
+
doc_id: params[:doc_id],
|
6
|
+
priority: params[:priority],
|
7
|
+
attempts: params[:attempts],
|
8
|
+
job_class: params[:job_class],
|
9
|
+
arguments: params[:arguments],
|
10
|
+
locked_by: params[:locked_by],
|
11
|
+
last_error: params[:last_error],
|
12
|
+
queue: params[:queue]
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def filter_param_query_empty?
|
17
|
+
filter_param_query.values.join.empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
module SettingsHelper
|
3
|
+
def current_theme
|
4
|
+
cookies[:rush_job_theme] == 'dark' ? 'dark' : 'light'
|
5
|
+
end
|
6
|
+
|
7
|
+
def invert_theme
|
8
|
+
cookies[:rush_job_theme] == 'dark' ? 'light' : 'dark'
|
9
|
+
end
|
10
|
+
|
11
|
+
def editing_enabled?
|
12
|
+
cookies[:rush_job_editing] == 'enabled'
|
13
|
+
end
|
14
|
+
|
15
|
+
def queue_groups_enabled?
|
16
|
+
cookies[:rush_job_queue_groups_presenter] != 'disabled'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class RushJob
|
3
|
+
include Mongoid::Document
|
4
|
+
|
5
|
+
store_in collection: 'delayed_backend_mongoid_jobs'
|
6
|
+
|
7
|
+
field :priority, type: Integer, default: 0
|
8
|
+
field :attempts, type: Integer, default: 0
|
9
|
+
field :handler, type: String
|
10
|
+
field :run_at, type: Time
|
11
|
+
field :locked_at, type: Time
|
12
|
+
field :locked_by, type: String
|
13
|
+
field :failed_at, type: Time
|
14
|
+
field :last_error, type: String
|
15
|
+
field :queue, type: String
|
16
|
+
|
17
|
+
validates :priority, presence: true
|
18
|
+
|
19
|
+
scope :locked_jobs, -> { where(:locked_at.exists => true) }
|
20
|
+
scope :locked_by_desc, -> { order_by(locked_by: -1, priority: 1, run_at: 1) }
|
21
|
+
scope :paginate, ->(page, jobs_per_page) { limit(jobs_per_page).skip(jobs_per_page * (page - 1)) }
|
22
|
+
scope :by_job_class, ->(job_class) { where(handler: /#{job_class}/i) if job_class.present? }
|
23
|
+
scope :by_arguments, ->(job_arguments) { where(handler: /#{job_arguments}/i) if job_arguments.present? }
|
24
|
+
scope :by_last_error, ->(last_error) { where(last_error: /#{last_error}/i) if last_error.present? }
|
25
|
+
|
26
|
+
%i[by_doc_id by_priority by_attempts by_locked_by by_queue].each do |where_query|
|
27
|
+
define_singleton_method where_query do |arg|
|
28
|
+
param = where_query.to_s.sub('by_', '').sub('doc', '')
|
29
|
+
arg.present? ? where(param => arg) : where({})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def job_class
|
34
|
+
job_data&.fetch(:job_class)
|
35
|
+
end
|
36
|
+
|
37
|
+
def job_arguments
|
38
|
+
job_data&.fetch(:arguments).presence || ''
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.queue_groups
|
42
|
+
groups = collection.aggregate([
|
43
|
+
{ '$group' => {
|
44
|
+
_id: { 'queue' => '$queue', 'priority' => '$priority' }, count: { '$sum' => 1 }
|
45
|
+
} }
|
46
|
+
]).to_a
|
47
|
+
|
48
|
+
group_result = []
|
49
|
+
|
50
|
+
groups.each do |group|
|
51
|
+
group_result << { queue: group['_id']['queue'], priority: group['_id']['priority'], count: group['count'] }
|
52
|
+
end
|
53
|
+
|
54
|
+
group_result.sort_by! { |group| [group[:priority], group[:queue]] }
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.clear_queue(queue_name, queue_priority)
|
58
|
+
where(queue: queue_name, priority: queue_priority).delete_all
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.filter(filter_params)
|
62
|
+
by_doc_id(filter_params[:doc_id])
|
63
|
+
.by_priority(filter_params[:priority])
|
64
|
+
.by_attempts(filter_params[:attempts])
|
65
|
+
.by_job_class(filter_params[:job_class])
|
66
|
+
.by_arguments(filter_params[:arguments])
|
67
|
+
.by_locked_by(filter_params[:locked_by])
|
68
|
+
.by_last_error(filter_params[:last_error])
|
69
|
+
.by_queue(filter_params[:queue])
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def handler_hash
|
75
|
+
safe_yaml = handler.sub('!ruby/object:ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper', '')
|
76
|
+
Psych.safe_load(safe_yaml, symbolize_names: true)
|
77
|
+
end
|
78
|
+
|
79
|
+
def job_data
|
80
|
+
handler_hash&.fetch(:job_data)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class PaginationPresenter
|
3
|
+
def initialize(page_param)
|
4
|
+
@page_param = page_param
|
5
|
+
end
|
6
|
+
|
7
|
+
def page
|
8
|
+
page = @page_param&.to_i || 1
|
9
|
+
|
10
|
+
[page, 1].max
|
11
|
+
end
|
12
|
+
|
13
|
+
def pages(item_count, items_per_page)
|
14
|
+
(item_count / items_per_page.to_f).ceil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class QueueGroupsPresenter
|
3
|
+
attr_reader :queue_groups_presenter, :rush_job_queue_groups, :queue_groups
|
4
|
+
|
5
|
+
def initialize(queue_groups_page)
|
6
|
+
@queue_groups_presenter = PaginationPresenter.new(queue_groups_page)
|
7
|
+
@rush_job_queue_groups = RushJob.queue_groups
|
8
|
+
@queue_groups = queue_groups_from_presener
|
9
|
+
end
|
10
|
+
|
11
|
+
def pages_count
|
12
|
+
@queue_groups_presenter.pages(@rush_job_queue_groups.count, 10)
|
13
|
+
end
|
14
|
+
|
15
|
+
def page
|
16
|
+
@queue_groups_presenter.page
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def queue_groups_from_presener
|
22
|
+
@rush_job_queue_groups[(@queue_groups_presenter.page - 1) * 10, 10]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class LockedJobs
|
3
|
+
def initialize(filters = {})
|
4
|
+
@filters = filters
|
5
|
+
end
|
6
|
+
|
7
|
+
def jobs
|
8
|
+
RushJob.filter(@filters).locked_jobs
|
9
|
+
end
|
10
|
+
|
11
|
+
def paginate(page, count_per_page = 10)
|
12
|
+
jobs.locked_by_desc.paginate(page, count_per_page)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RushJobMongoid
|
2
|
+
class Settings
|
3
|
+
RUSH_JOB_SETTINGS = {
|
4
|
+
theme: %w[light dark],
|
5
|
+
editing: %w[disabled enabled],
|
6
|
+
queue_groups_presenter: %w[enabled disabled]
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
def self.change_setting(setting, value)
|
10
|
+
return unless RUSH_JOB_SETTINGS[setting.to_sym]
|
11
|
+
|
12
|
+
if RUSH_JOB_SETTINGS[setting.to_sym].include?(value)
|
13
|
+
(RUSH_JOB_SETTINGS[setting.to_sym] - [value]).first
|
14
|
+
else
|
15
|
+
RUSH_JOB_SETTINGS[setting.to_sym].last
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<div class="modal fade" id="rush-job-mongoid-filter-modal" tabindex="-1" aria-labelledby="rushJobMongoidModalLabel" aria-hidden="true">
|
2
|
+
<div class="modal-dialog">
|
3
|
+
<div class="modal-content">
|
4
|
+
<div class="modal-header">
|
5
|
+
<h1 class="modal-title fs-5" id="rushJobMongoidModalLabel"><%= t(:filter_jobs) %></h1>
|
6
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
7
|
+
</div>
|
8
|
+
<%= form_with url: request.path, method: :get, data: { controller: 'rush-job-mongoid-filter' } do |form| %>
|
9
|
+
<div class="modal-body">
|
10
|
+
<div class="mb-3">
|
11
|
+
<%= form.label :doc_id, t(:id), class: 'form-label' %>
|
12
|
+
<%= form.text_field :doc_id, value: params[:doc_id], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="mb-3">
|
16
|
+
<%= form.label :priority, t(:priority), class: 'form-label' %>
|
17
|
+
<%= form.number_field :priority, value: params[:priority], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="mb-3">
|
21
|
+
<%= form.label :attempts, t(:attempts), class: 'form-label' %>
|
22
|
+
<%= form.number_field :attempts, value: params[:attempts], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="mb-3">
|
26
|
+
<%= form.label :job_class, t(:job_class), class: 'form-label' %>
|
27
|
+
<%= form.text_field :job_class, value: params[:job_class], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="mb-3">
|
31
|
+
<%= form.label :arguments, t(:arguments), class: 'form-label' %>
|
32
|
+
<%= form.text_field :arguments, value: params[:arguments], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div class="mb-3">
|
36
|
+
<%= form.label :locked_by, t(:locked_by), class: 'form-label' %>
|
37
|
+
<%= form.text_field :locked_by, value: params[:locked_by], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div class="mb-3">
|
41
|
+
<%= form.label :last_error, t(:last_error), class: 'form-label' %>
|
42
|
+
<%= form.text_field :last_error, value: params[:last_error], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
43
|
+
</div>
|
44
|
+
|
45
|
+
<div class="mb-3">
|
46
|
+
<%= form.label :queue, t(:queue), class: 'form-label' %>
|
47
|
+
<%= form.text_field :queue, value: params[:queue], class: 'form-control', data: { 'rush-job-mongoid-filter-target' => 'input' } %>
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
<div class="modal-footer">
|
51
|
+
<button type="button" class="btn btn-outline-secondary" data-action="click->rush-job-mongoid-filter#clearForm"><%= t(:clear) %></button>
|
52
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><%= t(:close) %></button>
|
53
|
+
<%= form.submit t(:filter), class: 'btn btn-primary' %>
|
54
|
+
</div>
|
55
|
+
<% end %>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
</div>
|