rails_workflow 0.3.9 → 0.4.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/Rakefile +2 -0
- data/app/concerns/rails_workflow/operation_status.rb +2 -0
- data/app/concerns/rails_workflow/operation_templates/assignments.rb +3 -1
- data/app/concerns/rails_workflow/operation_templates/dependencies.rb +18 -18
- data/app/concerns/rails_workflow/operations/assignments.rb +7 -5
- data/app/concerns/rails_workflow/operations/dependencies.rb +2 -0
- data/app/concerns/rails_workflow/status.rb +11 -15
- data/app/concerns/rails_workflow/user/assignment.rb +2 -0
- data/app/concerns/rails_workflow/uuid.rb +2 -0
- data/app/controllers/rails_workflow/application_controller.rb +2 -0
- data/app/controllers/rails_workflow/errors_controller.rb +2 -0
- data/app/controllers/rails_workflow/operation_templates_controller.rb +3 -1
- data/app/controllers/rails_workflow/operations_controller.rb +3 -1
- data/app/controllers/rails_workflow/process_templates_controller.rb +10 -8
- data/app/controllers/rails_workflow/processes_controller.rb +10 -8
- data/app/decorators/rails_workflow/context_decorator.rb +2 -0
- data/app/decorators/rails_workflow/decorator.rb +2 -0
- data/app/decorators/rails_workflow/operation_decorator.rb +2 -0
- data/app/decorators/rails_workflow/operation_helper_decorator.rb +2 -0
- data/app/decorators/rails_workflow/operation_template_decorator.rb +2 -0
- data/app/decorators/rails_workflow/paginating_decorator.rb +2 -0
- data/app/decorators/rails_workflow/process_decorator.rb +2 -0
- data/app/decorators/rails_workflow/process_template_decorator.rb +2 -0
- data/app/decorators/rails_workflow/status_decorator.rb +2 -0
- data/app/helpers/rails_workflow/application_helper.rb +2 -0
- data/app/jobs/rails_workflow/operation_execution_job.rb +11 -1
- data/app/models/rails_workflow/context.rb +3 -1
- data/app/models/rails_workflow/error.rb +23 -50
- data/app/models/rails_workflow/operation.rb +39 -3
- data/app/models/rails_workflow/operation_template.rb +2 -2
- data/app/models/rails_workflow/process.rb +34 -5
- data/app/models/rails_workflow/process_template.rb +12 -8
- data/app/models/rails_workflow/user_by_group_operation.rb +2 -0
- data/app/models/rails_workflow/user_by_role_operation.rb +2 -0
- data/app/models/rails_workflow/user_operation.rb +2 -0
- data/app/serializers/rails_workflow/operation_template_serializer.rb +2 -0
- data/app/serializers/rails_workflow/process_template_serializer.rb +2 -0
- data/app/services/rails_workflow/default_importer_preprocessor.rb +2 -0
- data/app/services/rails_workflow/process_importer.rb +2 -0
- data/app/views/rails_workflow/processes/index.html.slim +5 -5
- data/config/initializers/rails_workflow.rb +3 -3
- data/config/routes.rb +4 -2
- data/db/migrate/20150630174700_create_workflow_processes.rb +86 -84
- data/lib/generators/rails_workflow/install/install_generator.rb +2 -0
- data/lib/generators/rails_workflow/install/templates/create_workflow_processes.rb +86 -84
- data/lib/rails_workflow/config.rb +65 -24
- data/lib/rails_workflow/db/mysql.rb +3 -1
- data/lib/rails_workflow/db/pg.rb +3 -1
- data/lib/rails_workflow/dependency_resolver.rb +74 -0
- data/lib/rails_workflow/engine.rb +3 -1
- data/lib/rails_workflow/error_builder.rb +57 -0
- data/lib/rails_workflow/error_resolver.rb +72 -0
- data/lib/rails_workflow/operation_builder.rb +95 -0
- data/lib/rails_workflow/operation_runner.rb +113 -0
- data/lib/rails_workflow/process_builder.rb +57 -0
- data/lib/rails_workflow/process_manager.rb +66 -0
- data/lib/rails_workflow/process_runner.rb +72 -0
- data/lib/rails_workflow/version.rb +3 -1
- data/lib/rails_workflow.rb +2 -0
- data/lib/tasks/rails_workflow_tasks.rake +1 -0
- data/spec/concerns/status_spec.rb +25 -0
- data/spec/controllers/rails_workflow/operation_templates_controller_spec.rb +2 -0
- data/spec/controllers/rails_workflow/operations_controller_spec.rb +2 -0
- data/spec/controllers/rails_workflow/process_templates_controller_spec.rb +2 -0
- data/spec/controllers/rails_workflow/processes_controller_spec.rb +3 -1
- data/spec/dummy/Rakefile +2 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/controllers/leads_controller.rb +2 -0
- data/spec/dummy/app/controllers/sales_contacts_controller.rb +2 -0
- data/spec/dummy/app/decorators/lead_decorator.rb +2 -0
- data/spec/dummy/app/decorators/sales_contact_decorator.rb +2 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/leads_helper.rb +2 -0
- data/spec/dummy/app/helpers/sales_contacts_helper.rb +2 -0
- data/spec/dummy/app/models/bad_operation.rb +2 -0
- data/spec/dummy/app/models/bad_operation_template.rb +2 -0
- data/spec/dummy/app/models/lead.rb +2 -0
- data/spec/dummy/app/models/sales_contact.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/bin/bundle +2 -0
- data/spec/dummy/bin/rails +2 -0
- data/spec/dummy/bin/rake +2 -0
- data/spec/dummy/config/application.rb +2 -0
- data/spec/dummy/config/boot.rb +2 -0
- data/spec/dummy/config/database.yml.semaphore +2 -2
- data/spec/dummy/config/environment.rb +2 -0
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/production.rb +2 -0
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/config/initializers/assets.rb +2 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +2 -0
- data/spec/dummy/config/initializers/devise.rb +2 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +2 -0
- data/spec/dummy/config/initializers/inflections.rb +1 -0
- data/spec/dummy/config/initializers/mime_types.rb +1 -0
- data/spec/dummy/config/initializers/session_store.rb +2 -0
- data/spec/dummy/config/initializers/workflow.rb +2 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/config.ru +2 -0
- data/spec/dummy/db/migrate/20150127171613_devise_create_users.rb +2 -0
- data/spec/dummy/db/migrate/20150130042852_create_sales_contacts.rb +2 -0
- data/spec/dummy/db/migrate/20150130043008_create_leads.rb +2 -0
- data/spec/dummy/log/development.log +110 -0
- data/spec/dummy/log/test.log +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7O/7O5OddMZvWFGpj71BCdc0vA55rhj4YPoL0XjBV4_OYk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Cy/CyixQwp8QvorgpRadtYf6_zY35nZZp0JmrhkDN16XPM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/FW/FWR5Q7EP17cTcY35R1MscF6MX2HYiH5I2ZII89YLYxc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/HQ/HQuQO1k4kOyLSDXJEc8p-XR2agdkPF7mIFyh2noiNrU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/N4/N4e3G5QNTts2OVqkL0kxoP1xnAdDWnumpnH1m6WAsuY.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rs/RsIG_ias53xeb4WHWRodcMcDmVyz1QvLQNy4gV2iBSo.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/WI/WI2XYMfwCaPWcjvvouKVltl9oKqKZL-BHePPLhC-rzw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Yc/YcbQRZWzddLfawePxNTEXcFFiS7asAyrujZzciT99l0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ai/aihcJWCIJGiHDpamul8bzy4jMsxnhewX6XWtkdsQ9dc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fR/fRVQN4mU7z3MVJD9u1LMq8idpOH8o2tFh_YouMYGAM8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gU/gUFNMb7SgxFyz5ZZcGfp-VYRVIw711HUeiWonMzYrcU.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/h8/h86FNb4MxO5dq40P8KcCgGwZ_uqd8nn_O2fMWGDApW8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q7/q7cZDJXZFXTklMF8JAQSMr-MBxOKc7q1vZAPPR5RBf4.cache +2 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/s9/s98GbJDqEe4PG3moRH6h-ukIZmQz9Frq4LO_Z9vCBLM.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xX/xXCd205lXu7u_BuyBL0kfZwkBGJLvocHDItBfU6tMm4.cache +2 -0
- data/spec/factories/context.rb +2 -0
- data/spec/factories/operation_templates.rb +2 -0
- data/spec/factories/operations.rb +3 -1
- data/spec/factories/process_templates.rb +2 -0
- data/spec/factories/processes.rb +3 -1
- data/spec/factories/user.rb +2 -0
- data/spec/factories/workflow_errors.rb +2 -0
- data/spec/features/operations_spec.rb +2 -0
- data/spec/features/process_template_spec.rb +2 -0
- data/spec/lib/error_builder_spec.rb +137 -0
- data/spec/lib/error_resolver_spec.rb +182 -0
- data/spec/lib/operation_builder_spec.rb +69 -0
- data/spec/lib/process_builder_spec.rb +19 -0
- data/spec/{core/rails_workflow → lib}/process_manager_spec.rb +17 -27
- data/spec/models/rails_workflow/context_spec.rb +6 -3
- data/spec/models/rails_workflow/error_spec.rb +20 -147
- data/spec/models/rails_workflow/operation_spec.rb +64 -97
- data/spec/models/rails_workflow/operation_template_spec.rb +24 -11
- data/spec/models/rails_workflow/process_spec.rb +5 -2
- data/spec/models/rails_workflow/process_template_spec.rb +2 -36
- data/spec/rails_helper.rb +2 -0
- data/spec/serializers/process_template_serializer_spec.rb +2 -0
- data/spec/services/process_importer_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/controller_macros.rb +2 -0
- data/spec/support/pages/operations.rb +2 -0
- data/spec/support/rails_workflow/custom_operation.rb +2 -0
- data/spec/support/rails_workflow/custom_operation_template.rb +2 -0
- data/spec/{core → support}/rails_workflow/prepare_template.rb +3 -1
- data/spec/support/workflow_helper.rb +2 -0
- metadata +54 -28
- data/app/concerns/rails_workflow/operation_templates/default_builder.rb +0 -56
- data/app/concerns/rails_workflow/operations/default_runner.rb +0 -121
- data/app/concerns/rails_workflow/process_templates/default_builder.rb +0 -52
- data/app/concerns/rails_workflow/processes/default_runner.rb +0 -64
- data/app/concerns/rails_workflow/processes/dependency_resolver.rb +0 -54
- data/app/concerns/rails_workflow/reset_cache.rb +0 -13
- data/app/jobs/rails_workflow/operation_error_job.rb +0 -40
- data/app/managers/rails_workflow/process_manager.rb +0 -40
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsWorkflow
|
2
4
|
class Engine < ::Rails::Engine
|
3
5
|
isolate_namespace RailsWorkflow
|
@@ -17,7 +19,7 @@ module RailsWorkflow
|
|
17
19
|
end
|
18
20
|
|
19
21
|
initializer 'rails_workflow.assets.precompile' do |app|
|
20
|
-
app.config.assets.precompile += %w
|
22
|
+
app.config.assets.precompile += %w[application.css application.js]
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# Default error builder. Can be changed in configuration.
|
5
|
+
# Manages errors building
|
6
|
+
class ErrorBuilder
|
7
|
+
attr_accessor :exception, :context
|
8
|
+
|
9
|
+
def self.handle(exception, context)
|
10
|
+
new(exception, context).handle
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(exception, context)
|
14
|
+
@exception = exception
|
15
|
+
@context = context
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle
|
19
|
+
create_error(context)
|
20
|
+
process_parent(target)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def create_error(context)
|
26
|
+
error = RailsWorkflow::Error.create(
|
27
|
+
parent: target,
|
28
|
+
message: exception.message.first(250),
|
29
|
+
stack_trace: exception.backtrace.join("<br/>\n")
|
30
|
+
)
|
31
|
+
|
32
|
+
error.create_context(data: context)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Changing custom process or operation classes to default classes.
|
36
|
+
# If we store error with a custom class and somebody will delete
|
37
|
+
# or rename this class - we will not be able to load error.
|
38
|
+
def target
|
39
|
+
@target ||= begin
|
40
|
+
parent = context[:parent]
|
41
|
+
if parent.is_a? RailsWorkflow::Operation
|
42
|
+
parent.becomes(RailsWorkflow::Operation)
|
43
|
+
elsif parent.is_a? RailsWorkflow::Process
|
44
|
+
parent.becomes(RailsWorkflow::Process)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_parent(subject)
|
50
|
+
return if subject.nil?
|
51
|
+
|
52
|
+
subject.status = Status::ERROR
|
53
|
+
subject.save
|
54
|
+
process_parent(subject.parent) if subject.parent.present?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# Default error resolver. Can be changed in configuration.
|
5
|
+
# Manages errors processing
|
6
|
+
class ErrorResolver
|
7
|
+
attr_accessor :error
|
8
|
+
delegate :update_attribute, :target, :operation, :process,
|
9
|
+
:data, :can_restart_process?, to: :error
|
10
|
+
|
11
|
+
def self.retry(error)
|
12
|
+
new(error).retry
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(error)
|
16
|
+
@error = error
|
17
|
+
end
|
18
|
+
|
19
|
+
def retry
|
20
|
+
update_attribute(:resolved, true)
|
21
|
+
fix_status(error.parent)
|
22
|
+
prepared_target.send(data[:method], *data[:args])
|
23
|
+
try_restart_process unless target == 'process_manager'
|
24
|
+
end
|
25
|
+
|
26
|
+
def fix_status(subject)
|
27
|
+
subject.status = Status::IN_PROGRESS
|
28
|
+
subject.save
|
29
|
+
fix_status(subject.parent) if subject.parent.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepared_target
|
33
|
+
return operation_runner if target == 'operation_runner'
|
34
|
+
return operation_builder if target == 'operation_builder'
|
35
|
+
return dependency_resolver if target == 'dependency_resolver'
|
36
|
+
return process_manager if target == 'process_manager'
|
37
|
+
target
|
38
|
+
end
|
39
|
+
|
40
|
+
def try_restart_process
|
41
|
+
return unless process.present?
|
42
|
+
process.update_attribute(:status, Status::IN_PROGRESS)
|
43
|
+
|
44
|
+
process.reload
|
45
|
+
process_runner.start if can_restart_process?
|
46
|
+
end
|
47
|
+
|
48
|
+
def config
|
49
|
+
RailsWorkflow.config
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_manager
|
53
|
+
config.process_manager.new(process)
|
54
|
+
end
|
55
|
+
|
56
|
+
def operation_runner
|
57
|
+
config.operation_runner.new(operation)
|
58
|
+
end
|
59
|
+
|
60
|
+
def operation_builder
|
61
|
+
config.operation_builder.new(*data[:args]).tap { data[:args] = nil }
|
62
|
+
end
|
63
|
+
|
64
|
+
def dependency_resolver
|
65
|
+
config.dependency_resolver.new(process)
|
66
|
+
end
|
67
|
+
|
68
|
+
def process_runner
|
69
|
+
config.process_runner.new(process)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# Operation builder which creates new operaitons including
|
5
|
+
# their context, child processes etc... s
|
6
|
+
class OperationBuilder
|
7
|
+
attr_accessor :process, :template, :completed_dependencies
|
8
|
+
delegate :attributes, :operation_class, :child_process, to: :template
|
9
|
+
|
10
|
+
def initialize(process, template, completed_dependencies = [])
|
11
|
+
@process = process
|
12
|
+
@template = template
|
13
|
+
@completed_dependencies = completed_dependencies
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_operation
|
17
|
+
create_operation!.tap { |operation| process.operations << operation }
|
18
|
+
rescue => exception
|
19
|
+
handle_exception(exception)
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_operation!
|
23
|
+
operation = operation_class.create(prepared_attributes) do |op|
|
24
|
+
op.context = build_context(op, completed_dependencies)
|
25
|
+
# Can add OperationTemplate#after_operation_create callback
|
26
|
+
template.after_operation_create(op) if template.respond_to?(:after_operation_create)
|
27
|
+
end
|
28
|
+
|
29
|
+
build_child_process(operation)
|
30
|
+
operation
|
31
|
+
end
|
32
|
+
|
33
|
+
def prepared_dependencies
|
34
|
+
completed_dependencies.map do |dep|
|
35
|
+
{
|
36
|
+
operation_id: dep.id,
|
37
|
+
status: dep.status
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def prepared_attributes
|
45
|
+
attributes.with_indifferent_access
|
46
|
+
.slice(:title, :async, :is_background)
|
47
|
+
.merge(template: template,
|
48
|
+
process: process,
|
49
|
+
status: Operation::NOT_STARTED,
|
50
|
+
manager: process.manager,
|
51
|
+
dependencies: prepared_dependencies)
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_child_process(operation)
|
55
|
+
return unless child_process.present?
|
56
|
+
|
57
|
+
# TODO: replace with Process Builder or replace with
|
58
|
+
# config process manager
|
59
|
+
operation.child_process = RailsWorkflow::ProcessManager
|
60
|
+
.create_process(
|
61
|
+
child_process.id,
|
62
|
+
operation.context.data
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def prepare_context_data(dependencies)
|
67
|
+
dependencies.first.try(:context).try(:data)
|
68
|
+
end
|
69
|
+
|
70
|
+
# TODO: move to ContextBuilder
|
71
|
+
def build_context(operation, dependencies)
|
72
|
+
RailsWorkflow::Context.new(
|
73
|
+
parent: operation,
|
74
|
+
data: prepare_context_data(dependencies) || operation.process.data
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_exception(exception)
|
79
|
+
error_builder.handle(
|
80
|
+
exception,
|
81
|
+
parent: process, target: :operation_builder, method: :create_operation,
|
82
|
+
args: [process, template, completed_dependencies]
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def error_builder
|
87
|
+
config.error_builder
|
88
|
+
end
|
89
|
+
|
90
|
+
# TODO: move config
|
91
|
+
def config
|
92
|
+
RailsWorkflow.config
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# Workflow::OperationRunner responsible for operation execution
|
5
|
+
class OperationRunner
|
6
|
+
attr_accessor :operation
|
7
|
+
delegate :can_start?, :completed?, :completable?, :update_attribute,
|
8
|
+
:update_attributes, :is_background, :child_process, :context,
|
9
|
+
to: :operation
|
10
|
+
|
11
|
+
def self.start(operations)
|
12
|
+
operations.each do |operation|
|
13
|
+
new(operation).start
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(operation)
|
18
|
+
@operation = operation
|
19
|
+
end
|
20
|
+
|
21
|
+
def start
|
22
|
+
can_start? ? starting : waiting
|
23
|
+
rescue => exception
|
24
|
+
error_builder.handle(
|
25
|
+
exception,
|
26
|
+
parent: operation, target: :operation_runner, method: :start
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def starting
|
31
|
+
update_attribute(:status, Status::IN_PROGRESS)
|
32
|
+
|
33
|
+
if is_background && config.activejob_enabled
|
34
|
+
OperationExecutionJob.perform_later(operation.id)
|
35
|
+
else
|
36
|
+
OperationExecutionJob.perform_now(operation.id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def waiting
|
41
|
+
update_attribute(:status, Status::WAITING)
|
42
|
+
start_waiting if respond_to? :start_waiting
|
43
|
+
rescue => exception
|
44
|
+
error_builder.handle(
|
45
|
+
exception,
|
46
|
+
parent: operation,
|
47
|
+
target: :operation_runner,
|
48
|
+
method: :waiting
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def execute_in_transaction
|
53
|
+
with_transaction do
|
54
|
+
child_process_runner.start if child_process.present?
|
55
|
+
operation.execute if operation.respond_to?(:execute)
|
56
|
+
complete
|
57
|
+
end
|
58
|
+
rescue => exception
|
59
|
+
handle_exception(exception)
|
60
|
+
end
|
61
|
+
|
62
|
+
def complete(to_status = Status::DONE)
|
63
|
+
return unless completable?
|
64
|
+
|
65
|
+
context&.save
|
66
|
+
update_attributes(
|
67
|
+
status: to_status,
|
68
|
+
completed_at: Time.zone.now
|
69
|
+
)
|
70
|
+
process_runner.operation_completed(operation)
|
71
|
+
end
|
72
|
+
|
73
|
+
def cancel
|
74
|
+
complete Status::CANCELED
|
75
|
+
end
|
76
|
+
|
77
|
+
def skip
|
78
|
+
complete Status::SKIPPED
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def error_builder
|
84
|
+
config.error_builder
|
85
|
+
end
|
86
|
+
|
87
|
+
def handle_exception(exception)
|
88
|
+
error_builder.handle(
|
89
|
+
exception,
|
90
|
+
parent: operation, target: :operation_runner,
|
91
|
+
method: :execute_in_transaction
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def with_transaction
|
96
|
+
operation.class.transaction(requires_new: true) do
|
97
|
+
yield
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def child_process_runner
|
102
|
+
@child_process_runner ||= config.process_runner.new(child_process)
|
103
|
+
end
|
104
|
+
|
105
|
+
def process_runner
|
106
|
+
@process_runner ||= config.process_runner.new(operation.process)
|
107
|
+
end
|
108
|
+
|
109
|
+
def config
|
110
|
+
RailsWorkflow.config
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# = DefaultBuilder
|
5
|
+
#
|
6
|
+
# Process Builder is used to build new process. All process building logic
|
7
|
+
# should be gathered here. It defines how process is build using template
|
8
|
+
# (for example it can used to gather some additional information from
|
9
|
+
# system - for example some information from existing processes or it
|
10
|
+
# can handle hierarchical processes logic for parent / child processes).
|
11
|
+
class ProcessBuilder
|
12
|
+
attr_accessor :template, :context
|
13
|
+
|
14
|
+
delegate :process_class, :title, :independent_operations, to: :template
|
15
|
+
|
16
|
+
def initialize(template, context)
|
17
|
+
@template = template
|
18
|
+
@context = context
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_process!
|
22
|
+
process = process_class.create(template: template)
|
23
|
+
|
24
|
+
process.update_attributes(title: title, status: Process::NOT_STARTED)
|
25
|
+
process.create_context(data: context, parent: process)
|
26
|
+
|
27
|
+
build_independent_operations process
|
28
|
+
process
|
29
|
+
end
|
30
|
+
|
31
|
+
# Independent operations is template operations that have no
|
32
|
+
# dependencies from any other operations
|
33
|
+
def build_independent_operations(process)
|
34
|
+
independent_operations.each do |operation_template|
|
35
|
+
build_operation process, operation_template
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_operation(process, template, completed_dependencies = [])
|
40
|
+
operation_builder.new(
|
41
|
+
process, template, completed_dependencies
|
42
|
+
).create_operation
|
43
|
+
end
|
44
|
+
|
45
|
+
def error_builder
|
46
|
+
config.error_builder
|
47
|
+
end
|
48
|
+
|
49
|
+
def config
|
50
|
+
RailsWorkflow.config
|
51
|
+
end
|
52
|
+
|
53
|
+
def operation_builder
|
54
|
+
config.operation_builder
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsWorkflow
|
4
|
+
# ProcessManager should be used to build and start processes.
|
5
|
+
# It is top level hierarchy class that also can be used
|
6
|
+
# to build enhancements. For example they can be used to implement
|
7
|
+
# processes communications.
|
8
|
+
class ProcessManager
|
9
|
+
attr_accessor :process, :template, :context
|
10
|
+
# delegate :template, :operation_exception, to: :process
|
11
|
+
delegate :complete, to: :process, prefix: true
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def create_process(template_id, context)
|
15
|
+
new(template_id: template_id, context: context).create_process
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(process = nil, template_id: nil, context: nil)
|
20
|
+
@process = process
|
21
|
+
@template = ProcessTemplate.find(template_id) if template_id
|
22
|
+
@context = context
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_process
|
26
|
+
self.process = process_builder.new(template, context).create_process!
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.start_process(template_id, context)
|
30
|
+
process = create_process template_id, context
|
31
|
+
new(process).start_process
|
32
|
+
process
|
33
|
+
end
|
34
|
+
|
35
|
+
def start_process
|
36
|
+
process_runner.start
|
37
|
+
rescue => exception
|
38
|
+
error_builder.handle(
|
39
|
+
exception,
|
40
|
+
parent: process,
|
41
|
+
target: :process_manager,
|
42
|
+
method: :start_process
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def complete_process
|
47
|
+
process_runner.complete
|
48
|
+
end
|
49
|
+
|
50
|
+
def error_builder
|
51
|
+
config.error_builder
|
52
|
+
end
|
53
|
+
|
54
|
+
def process_builder
|
55
|
+
config.process_builder
|
56
|
+
end
|
57
|
+
|
58
|
+
def process_runner
|
59
|
+
@process_runner ||= config.process_runner.new(process)
|
60
|
+
end
|
61
|
+
|
62
|
+
def config
|
63
|
+
RailsWorkflow.config
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|