parent
b8bc50bb8d
commit
f7d4439f65
@ -1,23 +0,0 @@ |
||||
module Delayed |
||||
class Job |
||||
class Status < ApplicationRecord |
||||
self.table_name = 'delayed_job_statuses' |
||||
|
||||
belongs_to :user |
||||
belongs_to :reference, polymorphic: true |
||||
|
||||
enum status: { |
||||
in_queue: 'in_queue', |
||||
error: 'error', |
||||
in_process: 'in_process', |
||||
success: 'success', |
||||
failure: 'failure', |
||||
cancelled: 'cancelled' |
||||
} |
||||
|
||||
def self.of_reference(reference) |
||||
where(reference: reference) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,136 +0,0 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
module ActiveJob |
||||
class JobStatusListener |
||||
class << self |
||||
def register! |
||||
# Listen to enqueues |
||||
ActiveSupport::Notifications.subscribe(/enqueue(_at)?\.active_job/) do |_name, job:, **_args| |
||||
Rails.logger.debug { "Enqueuing background job #{job.inspect}" } |
||||
for_statused_jobs(job) { create_job_status(job) } |
||||
end |
||||
|
||||
# Start of process |
||||
ActiveSupport::Notifications.subscribe('perform_start.active_job') do |job:, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} is being started" } |
||||
for_statused_jobs(job) { on_start(job) } |
||||
end |
||||
|
||||
# Complete, or failure |
||||
ActiveSupport::Notifications.subscribe('perform.active_job') do |job:, exception_object: nil, **_args| |
||||
Rails.logger.debug do |
||||
successful = exception_object ? "with error: #{exception_object}" : "successful" |
||||
"Background job #{job.inspect} was performed #{successful}." |
||||
end |
||||
|
||||
for_statused_jobs(job) { on_performed(job, exception_object) } |
||||
end |
||||
|
||||
# Retry stopped -> failure |
||||
ActiveSupport::Notifications.subscribe('retry_stopped.active_job') do |job:, error: nil, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} no longer retrying due to: #{error}" } |
||||
for_statused_jobs(job) { on_performed(job, error) } |
||||
end |
||||
|
||||
# Retry enqueued |
||||
ActiveSupport::Notifications.subscribe('enqueue_retry.active_job') do |job, error: nil, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} is being retried after error: #{error}" } |
||||
for_statused_jobs(job) { on_requeue(job, error) } |
||||
end |
||||
|
||||
# Discarded job |
||||
ActiveSupport::Notifications.subscribe('discard.active_job') do |job:, error: nil, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} is being discarded after error: #{error}" } |
||||
for_statused_jobs(job) { on_cancelled(job, error) } |
||||
end |
||||
end |
||||
|
||||
private |
||||
|
||||
## |
||||
# Yiels the block if the job |
||||
# handles statuses |
||||
def for_statused_jobs(job) |
||||
yield if job.store_status? |
||||
end |
||||
|
||||
## |
||||
# Create a status object when enqueuing a |
||||
# new job through activejob that stores statuses |
||||
def create_job_status(job) |
||||
Delayed::Job::Status.create status: :in_queue, |
||||
reference: job.status_reference, |
||||
user: User.current, |
||||
job_id: job.job_id |
||||
end |
||||
|
||||
## |
||||
# On start processing a new job |
||||
def on_start(job) |
||||
update_status job, code: :in_process |
||||
end |
||||
|
||||
## |
||||
# On requeuing a job after error |
||||
def on_requeue(job, error) |
||||
update_status job, |
||||
code: :in_queue, |
||||
message: I18n.t('background_jobs.status.error_requeue', message: error) |
||||
end |
||||
|
||||
## |
||||
# On cancellation due to the given error |
||||
def on_cancelled(job, error) |
||||
update_status job, |
||||
code: :cancelled, |
||||
message: I18n.t('background_jobs.status.cancelled_due_to', message: error) |
||||
end |
||||
|
||||
## |
||||
# On job performed, update status |
||||
def on_performed(job, exception_object) |
||||
if exception_object |
||||
update_status job, |
||||
code: :failure, |
||||
message: exception_object.to_s |
||||
else |
||||
update_status job, code: :success |
||||
end |
||||
end |
||||
|
||||
## |
||||
# Update the status code for a given job |
||||
def update_status(job, code:, message: nil) |
||||
Delayed::Job::Status |
||||
.where(job_id: job.job_id) |
||||
.update_all(status: code, message: message) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1 @@ |
||||
Hello {{jobId}} |
@ -0,0 +1,12 @@ |
||||
import {Component} from "@angular/core"; |
||||
import {StateService} from "@uirouter/core"; |
||||
|
||||
@Component({ |
||||
templateUrl: './display-job-page.component.html' |
||||
}) |
||||
export class DisplayJobPageComponent { |
||||
jobId:string = this.$state.params.jobId; |
||||
|
||||
constructor(private $state:StateService) { |
||||
} |
||||
} |
@ -0,0 +1,68 @@ |
||||
// -- copyright
|
||||
// OpenProject is an open source project management software.
|
||||
// Copyright (C) 2012-2020 the OpenProject GmbH
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License version 3.
|
||||
//
|
||||
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// See docs/COPYRIGHT.rdoc for more details.
|
||||
// ++
|
||||
|
||||
import {OpenprojectCommonModule} from 'core-app/modules/common/openproject-common.module'; |
||||
import {NgModule} from '@angular/core'; |
||||
import {FullCalendarModule} from '@fullcalendar/angular'; |
||||
import {WorkPackagesCalendarEntryComponent} from "core-app/modules/calendar/wp-calendar-entry/wp-calendar-entry.component"; |
||||
import {WorkPackagesCalendarController} from "core-app/modules/calendar/wp-calendar/wp-calendar.component"; |
||||
import {OpenprojectWorkPackagesModule} from "core-app/modules/work_packages/openproject-work-packages.module"; |
||||
import {Ng2StateDeclaration, UIRouterModule} from "@uirouter/angular"; |
||||
import {TimeEntryCalendarComponent} from "core-app/modules/calendar/te-calendar/te-calendar.component"; |
||||
import {OpenprojectFieldsModule} from "core-app/modules/fields/openproject-fields.module"; |
||||
import {OpenprojectTimeEntriesModule} from "core-app/modules/time_entries/openproject-time-entries.module"; |
||||
import {DisplayJobPageComponent} from "core-app/modules/job-status/display-job-page/display-job-page.component"; |
||||
import {ApplicationBaseComponent} from "core-app/modules/router/base/application-base.component"; |
||||
|
||||
export const JOB_STATUS_ROUTE:Ng2StateDeclaration[] = [ |
||||
{ |
||||
name: 'job-statuses', |
||||
url: '/job_statuses/{jobId:[a-z0-9-]+}', |
||||
parent: 'root', |
||||
component: DisplayJobPageComponent, |
||||
data: { |
||||
bodyClasses: 'router--job-statuses' |
||||
} |
||||
} |
||||
]; |
||||
|
||||
@NgModule({ |
||||
imports: [ |
||||
// Commons
|
||||
OpenprojectCommonModule, |
||||
|
||||
// Routes for /job_statuses/:uuid
|
||||
UIRouterModule.forChild({ states: JOB_STATUS_ROUTE }), |
||||
|
||||
], |
||||
declarations: [ |
||||
DisplayJobPageComponent |
||||
] |
||||
}) |
||||
export class OpenProjectJobStatusModule { |
||||
} |
@ -0,0 +1,51 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
module JobStatus |
||||
class JobStatusesController < ::ApplicationController |
||||
before_action :authorize_on_job |
||||
layout 'angular' |
||||
|
||||
def show |
||||
# Frontend will handle rendering |
||||
# but we will need to render with layout |
||||
render html: '', layout: true |
||||
end |
||||
|
||||
private |
||||
|
||||
def authorize_on_job |
||||
return if JobStatus::Status |
||||
.where(job_id: params[:job_uuid], user_id: current_user.id) |
||||
.exists? |
||||
|
||||
render_404 |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,21 @@ |
||||
module JobStatus |
||||
class Status < ApplicationRecord |
||||
self.table_name = 'delayed_job_statuses' |
||||
|
||||
belongs_to :user |
||||
belongs_to :reference, polymorphic: true |
||||
|
||||
enum status: { |
||||
in_queue: 'in_queue', |
||||
error: 'error', |
||||
in_process: 'in_process', |
||||
success: 'success', |
||||
failure: 'failure', |
||||
cancelled: 'cancelled' |
||||
} |
||||
|
||||
def self.of_reference(reference) |
||||
where(reference: reference) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,6 @@ |
||||
OpenProject::Application.routes.draw do |
||||
resources :job_statuses, |
||||
param: :job_uuid, |
||||
controller: 'job_status/job_statuses', |
||||
only: %i[show] |
||||
end |
@ -0,0 +1,50 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
require 'open_project/plugins' |
||||
|
||||
module OpenProject::JobStatus |
||||
class Engine < ::Rails::Engine |
||||
engine_name :openproject_job_status |
||||
|
||||
include OpenProject::Plugins::ActsAsOpEngine |
||||
|
||||
register 'openproject-job_status', |
||||
author_url: 'https://www.openproject.com', |
||||
bundled: true |
||||
|
||||
config.to_prepare do |
||||
# Extends the ActiveJob adapter in use (DelayedJob) by a Status which lives |
||||
# indenpendently from the job itself (which is deleted once successful or after max attempts). |
||||
# That way, the result of a background job is available even after the original job is gone. |
||||
|
||||
EventListener.register! |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,138 @@ |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
module OpenProject |
||||
module JobStatus |
||||
class EventListener |
||||
class << self |
||||
def register! |
||||
# Listen to enqueues |
||||
ActiveSupport::Notifications.subscribe(/enqueue(_at)?\.active_job/) do |_name, job:, **_args| |
||||
Rails.logger.debug { "Enqueuing background job #{job.inspect}" } |
||||
for_statused_jobs(job) { create_job_status(job) } |
||||
end |
||||
|
||||
# Start of process |
||||
ActiveSupport::Notifications.subscribe('perform_start.active_job') do |job:, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} is being started" } |
||||
for_statused_jobs(job) { on_start(job) } |
||||
end |
||||
|
||||
# Complete, or failure |
||||
ActiveSupport::Notifications.subscribe('perform.active_job') do |job:, exception_object: nil, **_args| |
||||
Rails.logger.debug do |
||||
successful = exception_object ? "with error: #{exception_object}" : "successful" |
||||
"Background job #{job.inspect} was performed #{successful}." |
||||
end |
||||
|
||||
for_statused_jobs(job) { on_performed(job, exception_object) } |
||||
end |
||||
|
||||
# Retry stopped -> failure |
||||
ActiveSupport::Notifications.subscribe('retry_stopped.active_job') do |job:, error: nil, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} no longer retrying due to: #{error}" } |
||||
for_statused_jobs(job) { on_performed(job, error) } |
||||
end |
||||
|
||||
# Retry enqueued |
||||
ActiveSupport::Notifications.subscribe('enqueue_retry.active_job') do |job, error: nil, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} is being retried after error: #{error}" } |
||||
for_statused_jobs(job) { on_requeue(job, error) } |
||||
end |
||||
|
||||
# Discarded job |
||||
ActiveSupport::Notifications.subscribe('discard.active_job') do |job:, error: nil, **_args| |
||||
Rails.logger.debug { "Background job #{job.inspect} is being discarded after error: #{error}" } |
||||
for_statused_jobs(job) { on_cancelled(job, error) } |
||||
end |
||||
end |
||||
|
||||
private |
||||
|
||||
## |
||||
# Yiels the block if the job |
||||
# handles statuses |
||||
def for_statused_jobs(job) |
||||
yield if job.store_status? |
||||
end |
||||
|
||||
## |
||||
# Create a status object when enqueuing a |
||||
# new job through activejob that stores statuses |
||||
def create_job_status(job) |
||||
Delayed::Job::Status.create status: :in_queue, |
||||
reference: job.status_reference, |
||||
user: User.current, |
||||
job_id: job.job_id |
||||
end |
||||
|
||||
## |
||||
# On start processing a new job |
||||
def on_start(job) |
||||
update_status job, code: :in_process |
||||
end |
||||
|
||||
## |
||||
# On requeuing a job after error |
||||
def on_requeue(job, error) |
||||
update_status job, |
||||
code: :in_queue, |
||||
message: I18n.t('background_jobs.status.error_requeue', message: error) |
||||
end |
||||
|
||||
## |
||||
# On cancellation due to the given error |
||||
def on_cancelled(job, error) |
||||
update_status job, |
||||
code: :cancelled, |
||||
message: I18n.t('background_jobs.status.cancelled_due_to', message: error) |
||||
end |
||||
|
||||
## |
||||
# On job performed, update status |
||||
def on_performed(job, exception_object) |
||||
if exception_object |
||||
update_status job, |
||||
code: :failure, |
||||
message: exception_object.to_s |
||||
else |
||||
update_status job, code: :success |
||||
end |
||||
end |
||||
|
||||
## |
||||
# Update the status code for a given job |
||||
def update_status(job, code:, message: nil) |
||||
Delayed::Job::Status |
||||
.where(job_id: job.job_id) |
||||
.update_all(status: code, message: message) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,30 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is an open source project management software. |
||||
# Copyright (C) 2012-2020 the OpenProject GmbH |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See docs/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
require 'open_project/job_status' |
@ -0,0 +1,11 @@ |
||||
# encoding: UTF-8 |
||||
|
||||
Gem::Specification.new do |s| |
||||
s.name = 'openproject-job_status' |
||||
s.version = '1.0.0' |
||||
s.authors = 'OpenProject GmbH' |
||||
s.email = 'info@openproject.com' |
||||
s.summary = 'OpenProject Job status' |
||||
s.description = 'Listing and status of background jobs' |
||||
s.license = 'GPLv3' |
||||
end |
Loading…
Reference in new issue