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.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -0
  3. data/app/concerns/rails_workflow/operation_status.rb +2 -0
  4. data/app/concerns/rails_workflow/operation_templates/assignments.rb +3 -1
  5. data/app/concerns/rails_workflow/operation_templates/dependencies.rb +18 -18
  6. data/app/concerns/rails_workflow/operations/assignments.rb +7 -5
  7. data/app/concerns/rails_workflow/operations/dependencies.rb +2 -0
  8. data/app/concerns/rails_workflow/status.rb +11 -15
  9. data/app/concerns/rails_workflow/user/assignment.rb +2 -0
  10. data/app/concerns/rails_workflow/uuid.rb +2 -0
  11. data/app/controllers/rails_workflow/application_controller.rb +2 -0
  12. data/app/controllers/rails_workflow/errors_controller.rb +2 -0
  13. data/app/controllers/rails_workflow/operation_templates_controller.rb +3 -1
  14. data/app/controllers/rails_workflow/operations_controller.rb +3 -1
  15. data/app/controllers/rails_workflow/process_templates_controller.rb +10 -8
  16. data/app/controllers/rails_workflow/processes_controller.rb +10 -8
  17. data/app/decorators/rails_workflow/context_decorator.rb +2 -0
  18. data/app/decorators/rails_workflow/decorator.rb +2 -0
  19. data/app/decorators/rails_workflow/operation_decorator.rb +2 -0
  20. data/app/decorators/rails_workflow/operation_helper_decorator.rb +2 -0
  21. data/app/decorators/rails_workflow/operation_template_decorator.rb +2 -0
  22. data/app/decorators/rails_workflow/paginating_decorator.rb +2 -0
  23. data/app/decorators/rails_workflow/process_decorator.rb +2 -0
  24. data/app/decorators/rails_workflow/process_template_decorator.rb +2 -0
  25. data/app/decorators/rails_workflow/status_decorator.rb +2 -0
  26. data/app/helpers/rails_workflow/application_helper.rb +2 -0
  27. data/app/jobs/rails_workflow/operation_execution_job.rb +11 -1
  28. data/app/models/rails_workflow/context.rb +3 -1
  29. data/app/models/rails_workflow/error.rb +23 -50
  30. data/app/models/rails_workflow/operation.rb +39 -3
  31. data/app/models/rails_workflow/operation_template.rb +2 -2
  32. data/app/models/rails_workflow/process.rb +34 -5
  33. data/app/models/rails_workflow/process_template.rb +12 -8
  34. data/app/models/rails_workflow/user_by_group_operation.rb +2 -0
  35. data/app/models/rails_workflow/user_by_role_operation.rb +2 -0
  36. data/app/models/rails_workflow/user_operation.rb +2 -0
  37. data/app/serializers/rails_workflow/operation_template_serializer.rb +2 -0
  38. data/app/serializers/rails_workflow/process_template_serializer.rb +2 -0
  39. data/app/services/rails_workflow/default_importer_preprocessor.rb +2 -0
  40. data/app/services/rails_workflow/process_importer.rb +2 -0
  41. data/app/views/rails_workflow/processes/index.html.slim +5 -5
  42. data/config/initializers/rails_workflow.rb +3 -3
  43. data/config/routes.rb +4 -2
  44. data/db/migrate/20150630174700_create_workflow_processes.rb +86 -84
  45. data/lib/generators/rails_workflow/install/install_generator.rb +2 -0
  46. data/lib/generators/rails_workflow/install/templates/create_workflow_processes.rb +86 -84
  47. data/lib/rails_workflow/config.rb +65 -24
  48. data/lib/rails_workflow/db/mysql.rb +3 -1
  49. data/lib/rails_workflow/db/pg.rb +3 -1
  50. data/lib/rails_workflow/dependency_resolver.rb +74 -0
  51. data/lib/rails_workflow/engine.rb +3 -1
  52. data/lib/rails_workflow/error_builder.rb +57 -0
  53. data/lib/rails_workflow/error_resolver.rb +72 -0
  54. data/lib/rails_workflow/operation_builder.rb +95 -0
  55. data/lib/rails_workflow/operation_runner.rb +113 -0
  56. data/lib/rails_workflow/process_builder.rb +57 -0
  57. data/lib/rails_workflow/process_manager.rb +66 -0
  58. data/lib/rails_workflow/process_runner.rb +72 -0
  59. data/lib/rails_workflow/version.rb +3 -1
  60. data/lib/rails_workflow.rb +2 -0
  61. data/lib/tasks/rails_workflow_tasks.rake +1 -0
  62. data/spec/concerns/status_spec.rb +25 -0
  63. data/spec/controllers/rails_workflow/operation_templates_controller_spec.rb +2 -0
  64. data/spec/controllers/rails_workflow/operations_controller_spec.rb +2 -0
  65. data/spec/controllers/rails_workflow/process_templates_controller_spec.rb +2 -0
  66. data/spec/controllers/rails_workflow/processes_controller_spec.rb +3 -1
  67. data/spec/dummy/Rakefile +2 -0
  68. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  69. data/spec/dummy/app/controllers/leads_controller.rb +2 -0
  70. data/spec/dummy/app/controllers/sales_contacts_controller.rb +2 -0
  71. data/spec/dummy/app/decorators/lead_decorator.rb +2 -0
  72. data/spec/dummy/app/decorators/sales_contact_decorator.rb +2 -0
  73. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  74. data/spec/dummy/app/helpers/leads_helper.rb +2 -0
  75. data/spec/dummy/app/helpers/sales_contacts_helper.rb +2 -0
  76. data/spec/dummy/app/models/bad_operation.rb +2 -0
  77. data/spec/dummy/app/models/bad_operation_template.rb +2 -0
  78. data/spec/dummy/app/models/lead.rb +2 -0
  79. data/spec/dummy/app/models/sales_contact.rb +2 -0
  80. data/spec/dummy/app/models/user.rb +2 -0
  81. data/spec/dummy/bin/bundle +2 -0
  82. data/spec/dummy/bin/rails +2 -0
  83. data/spec/dummy/bin/rake +2 -0
  84. data/spec/dummy/config/application.rb +2 -0
  85. data/spec/dummy/config/boot.rb +2 -0
  86. data/spec/dummy/config/database.yml.semaphore +2 -2
  87. data/spec/dummy/config/environment.rb +2 -0
  88. data/spec/dummy/config/environments/development.rb +2 -0
  89. data/spec/dummy/config/environments/production.rb +2 -0
  90. data/spec/dummy/config/environments/test.rb +2 -0
  91. data/spec/dummy/config/initializers/assets.rb +2 -0
  92. data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
  93. data/spec/dummy/config/initializers/cookies_serializer.rb +2 -0
  94. data/spec/dummy/config/initializers/devise.rb +2 -0
  95. data/spec/dummy/config/initializers/filter_parameter_logging.rb +2 -0
  96. data/spec/dummy/config/initializers/inflections.rb +1 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +1 -0
  98. data/spec/dummy/config/initializers/session_store.rb +2 -0
  99. data/spec/dummy/config/initializers/workflow.rb +2 -0
  100. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  101. data/spec/dummy/config/routes.rb +2 -0
  102. data/spec/dummy/config.ru +2 -0
  103. data/spec/dummy/db/migrate/20150127171613_devise_create_users.rb +2 -0
  104. data/spec/dummy/db/migrate/20150130042852_create_sales_contacts.rb +2 -0
  105. data/spec/dummy/db/migrate/20150130043008_create_leads.rb +2 -0
  106. data/spec/dummy/log/development.log +110 -0
  107. data/spec/dummy/log/test.log +0 -0
  108. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7O/7O5OddMZvWFGpj71BCdc0vA55rhj4YPoL0XjBV4_OYk.cache +1 -0
  109. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Cy/CyixQwp8QvorgpRadtYf6_zY35nZZp0JmrhkDN16XPM.cache +1 -0
  110. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/FW/FWR5Q7EP17cTcY35R1MscF6MX2HYiH5I2ZII89YLYxc.cache +1 -0
  111. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/HQ/HQuQO1k4kOyLSDXJEc8p-XR2agdkPF7mIFyh2noiNrU.cache +1 -0
  112. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/N4/N4e3G5QNTts2OVqkL0kxoP1xnAdDWnumpnH1m6WAsuY.cache +0 -0
  113. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rs/RsIG_ias53xeb4WHWRodcMcDmVyz1QvLQNy4gV2iBSo.cache +1 -0
  114. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/WI/WI2XYMfwCaPWcjvvouKVltl9oKqKZL-BHePPLhC-rzw.cache +1 -0
  115. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Yc/YcbQRZWzddLfawePxNTEXcFFiS7asAyrujZzciT99l0.cache +1 -0
  116. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ai/aihcJWCIJGiHDpamul8bzy4jMsxnhewX6XWtkdsQ9dc.cache +1 -0
  117. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fR/fRVQN4mU7z3MVJD9u1LMq8idpOH8o2tFh_YouMYGAM8.cache +1 -0
  118. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gU/gUFNMb7SgxFyz5ZZcGfp-VYRVIw711HUeiWonMzYrcU.cache +1 -0
  119. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/h8/h86FNb4MxO5dq40P8KcCgGwZ_uqd8nn_O2fMWGDApW8.cache +1 -0
  120. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q7/q7cZDJXZFXTklMF8JAQSMr-MBxOKc7q1vZAPPR5RBf4.cache +2 -0
  121. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/s9/s98GbJDqEe4PG3moRH6h-ukIZmQz9Frq4LO_Z9vCBLM.cache +1 -0
  122. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xX/xXCd205lXu7u_BuyBL0kfZwkBGJLvocHDItBfU6tMm4.cache +2 -0
  123. data/spec/factories/context.rb +2 -0
  124. data/spec/factories/operation_templates.rb +2 -0
  125. data/spec/factories/operations.rb +3 -1
  126. data/spec/factories/process_templates.rb +2 -0
  127. data/spec/factories/processes.rb +3 -1
  128. data/spec/factories/user.rb +2 -0
  129. data/spec/factories/workflow_errors.rb +2 -0
  130. data/spec/features/operations_spec.rb +2 -0
  131. data/spec/features/process_template_spec.rb +2 -0
  132. data/spec/lib/error_builder_spec.rb +137 -0
  133. data/spec/lib/error_resolver_spec.rb +182 -0
  134. data/spec/lib/operation_builder_spec.rb +69 -0
  135. data/spec/lib/process_builder_spec.rb +19 -0
  136. data/spec/{core/rails_workflow → lib}/process_manager_spec.rb +17 -27
  137. data/spec/models/rails_workflow/context_spec.rb +6 -3
  138. data/spec/models/rails_workflow/error_spec.rb +20 -147
  139. data/spec/models/rails_workflow/operation_spec.rb +64 -97
  140. data/spec/models/rails_workflow/operation_template_spec.rb +24 -11
  141. data/spec/models/rails_workflow/process_spec.rb +5 -2
  142. data/spec/models/rails_workflow/process_template_spec.rb +2 -36
  143. data/spec/rails_helper.rb +2 -0
  144. data/spec/serializers/process_template_serializer_spec.rb +2 -0
  145. data/spec/services/process_importer_spec.rb +2 -0
  146. data/spec/spec_helper.rb +2 -0
  147. data/spec/support/controller_macros.rb +2 -0
  148. data/spec/support/pages/operations.rb +2 -0
  149. data/spec/support/rails_workflow/custom_operation.rb +2 -0
  150. data/spec/support/rails_workflow/custom_operation_template.rb +2 -0
  151. data/spec/{core → support}/rails_workflow/prepare_template.rb +3 -1
  152. data/spec/support/workflow_helper.rb +2 -0
  153. metadata +54 -28
  154. data/app/concerns/rails_workflow/operation_templates/default_builder.rb +0 -56
  155. data/app/concerns/rails_workflow/operations/default_runner.rb +0 -121
  156. data/app/concerns/rails_workflow/process_templates/default_builder.rb +0 -52
  157. data/app/concerns/rails_workflow/processes/default_runner.rb +0 -64
  158. data/app/concerns/rails_workflow/processes/dependency_resolver.rb +0 -54
  159. data/app/concerns/rails_workflow/reset_cache.rb +0 -13
  160. data/app/jobs/rails_workflow/operation_error_job.rb +0 -40
  161. 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(application.css application.js)
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