rails_workflow 0.3.9 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|