dynflow 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. data/.gitignore +6 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +0 -10
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +99 -37
  6. data/Rakefile +2 -6
  7. data/doc/images/logo.png +0 -0
  8. data/dynflow.gemspec +10 -1
  9. data/examples/generate_work_for_daemon.rb +24 -0
  10. data/examples/orchestrate.rb +121 -0
  11. data/examples/run_daemon.rb +17 -0
  12. data/examples/web_console.rb +29 -0
  13. data/lib/dynflow.rb +27 -6
  14. data/lib/dynflow/action.rb +185 -77
  15. data/lib/dynflow/action/cancellable_polling.rb +18 -0
  16. data/lib/dynflow/action/finalize_phase.rb +18 -0
  17. data/lib/dynflow/action/flow_phase.rb +44 -0
  18. data/lib/dynflow/action/format.rb +46 -0
  19. data/lib/dynflow/action/missing.rb +26 -0
  20. data/lib/dynflow/action/plan_phase.rb +85 -0
  21. data/lib/dynflow/action/polling.rb +49 -0
  22. data/lib/dynflow/action/presenter.rb +51 -0
  23. data/lib/dynflow/action/progress.rb +62 -0
  24. data/lib/dynflow/action/run_phase.rb +43 -0
  25. data/lib/dynflow/action/suspended.rb +21 -0
  26. data/lib/dynflow/clock.rb +133 -0
  27. data/lib/dynflow/daemon.rb +29 -0
  28. data/lib/dynflow/execution_plan.rb +285 -33
  29. data/lib/dynflow/execution_plan/dependency_graph.rb +29 -0
  30. data/lib/dynflow/execution_plan/output_reference.rb +52 -0
  31. data/lib/dynflow/execution_plan/steps.rb +12 -0
  32. data/lib/dynflow/execution_plan/steps/abstract.rb +121 -0
  33. data/lib/dynflow/execution_plan/steps/abstract_flow_step.rb +52 -0
  34. data/lib/dynflow/execution_plan/steps/error.rb +33 -0
  35. data/lib/dynflow/execution_plan/steps/finalize_step.rb +23 -0
  36. data/lib/dynflow/execution_plan/steps/plan_step.rb +81 -0
  37. data/lib/dynflow/execution_plan/steps/run_step.rb +21 -0
  38. data/lib/dynflow/executors.rb +9 -0
  39. data/lib/dynflow/executors/abstract.rb +32 -0
  40. data/lib/dynflow/executors/parallel.rb +88 -0
  41. data/lib/dynflow/executors/parallel/core.rb +119 -0
  42. data/lib/dynflow/executors/parallel/execution_plan_manager.rb +120 -0
  43. data/lib/dynflow/executors/parallel/flow_manager.rb +48 -0
  44. data/lib/dynflow/executors/parallel/pool.rb +102 -0
  45. data/lib/dynflow/executors/parallel/running_steps_manager.rb +63 -0
  46. data/lib/dynflow/executors/parallel/sequence_cursor.rb +97 -0
  47. data/lib/dynflow/executors/parallel/sequential_manager.rb +81 -0
  48. data/lib/dynflow/executors/parallel/work_queue.rb +44 -0
  49. data/lib/dynflow/executors/parallel/worker.rb +30 -0
  50. data/lib/dynflow/executors/remote_via_socket.rb +38 -0
  51. data/lib/dynflow/executors/remote_via_socket/core.rb +150 -0
  52. data/lib/dynflow/flows.rb +13 -0
  53. data/lib/dynflow/flows/abstract.rb +36 -0
  54. data/lib/dynflow/flows/abstract_composed.rb +104 -0
  55. data/lib/dynflow/flows/atom.rb +36 -0
  56. data/lib/dynflow/flows/concurrence.rb +28 -0
  57. data/lib/dynflow/flows/sequence.rb +13 -0
  58. data/lib/dynflow/future.rb +173 -0
  59. data/lib/dynflow/listeners.rb +7 -0
  60. data/lib/dynflow/listeners/abstract.rb +13 -0
  61. data/lib/dynflow/listeners/serialization.rb +41 -0
  62. data/lib/dynflow/listeners/socket.rb +88 -0
  63. data/lib/dynflow/logger_adapters.rb +8 -0
  64. data/lib/dynflow/logger_adapters/abstract.rb +30 -0
  65. data/lib/dynflow/logger_adapters/delegator.rb +13 -0
  66. data/lib/dynflow/logger_adapters/formatters.rb +8 -0
  67. data/lib/dynflow/logger_adapters/formatters/abstract.rb +33 -0
  68. data/lib/dynflow/logger_adapters/formatters/exception.rb +15 -0
  69. data/lib/dynflow/logger_adapters/simple.rb +59 -0
  70. data/lib/dynflow/micro_actor.rb +102 -0
  71. data/lib/dynflow/persistence.rb +53 -0
  72. data/lib/dynflow/persistence_adapters.rb +6 -0
  73. data/lib/dynflow/persistence_adapters/abstract.rb +56 -0
  74. data/lib/dynflow/persistence_adapters/sequel.rb +160 -0
  75. data/lib/dynflow/persistence_adapters/sequel_migrations/001_initial.rb +52 -0
  76. data/lib/dynflow/serializable.rb +66 -0
  77. data/lib/dynflow/simple_world.rb +18 -0
  78. data/lib/dynflow/stateful.rb +40 -0
  79. data/lib/dynflow/testing.rb +32 -0
  80. data/lib/dynflow/testing/assertions.rb +64 -0
  81. data/lib/dynflow/testing/dummy_execution_plan.rb +40 -0
  82. data/lib/dynflow/testing/dummy_executor.rb +29 -0
  83. data/lib/dynflow/testing/dummy_planned_action.rb +18 -0
  84. data/lib/dynflow/testing/dummy_step.rb +19 -0
  85. data/lib/dynflow/testing/dummy_world.rb +33 -0
  86. data/lib/dynflow/testing/factories.rb +83 -0
  87. data/lib/dynflow/testing/managed_clock.rb +23 -0
  88. data/lib/dynflow/testing/mimic.rb +38 -0
  89. data/lib/dynflow/transaction_adapters.rb +9 -0
  90. data/lib/dynflow/transaction_adapters/abstract.rb +26 -0
  91. data/lib/dynflow/transaction_adapters/active_record.rb +27 -0
  92. data/lib/dynflow/transaction_adapters/none.rb +12 -0
  93. data/lib/dynflow/version.rb +1 -1
  94. data/lib/dynflow/web_console.rb +277 -0
  95. data/lib/dynflow/world.rb +168 -0
  96. data/test/action_test.rb +89 -11
  97. data/test/clock_test.rb +59 -0
  98. data/test/code_workflow_example.rb +382 -0
  99. data/test/execution_plan_test.rb +195 -64
  100. data/test/executor_test.rb +692 -0
  101. data/test/persistance_adapters_test.rb +173 -0
  102. data/test/test_helper.rb +316 -1
  103. data/test/testing_test.rb +148 -0
  104. data/test/web_console_test.rb +38 -0
  105. data/web/assets/javascripts/application.js +25 -0
  106. data/web/assets/stylesheets/application.css +101 -0
  107. data/web/assets/vendor/bootstrap/css/bootstrap-responsive.css +1109 -0
  108. data/web/assets/vendor/bootstrap/css/bootstrap-responsive.min.css +9 -0
  109. data/web/assets/vendor/bootstrap/css/bootstrap.css +6167 -0
  110. data/web/assets/vendor/bootstrap/css/bootstrap.min.css +9 -0
  111. data/web/assets/vendor/bootstrap/img/glyphicons-halflings-white.png +0 -0
  112. data/web/assets/vendor/bootstrap/img/glyphicons-halflings.png +0 -0
  113. data/web/assets/vendor/bootstrap/js/bootstrap.js +2280 -0
  114. data/web/assets/vendor/bootstrap/js/bootstrap.min.js +6 -0
  115. data/web/assets/vendor/google-code-prettify/lang-basic.js +3 -0
  116. data/web/assets/vendor/google-code-prettify/prettify.css +1 -0
  117. data/web/assets/vendor/google-code-prettify/prettify.js +30 -0
  118. data/web/assets/vendor/google-code-prettify/run_prettify.js +34 -0
  119. data/web/assets/vendor/jquery/jquery.js +9807 -0
  120. data/web/views/flow.erb +19 -0
  121. data/web/views/flow_step.erb +31 -0
  122. data/web/views/index.erb +39 -0
  123. data/web/views/layout.erb +20 -0
  124. data/web/views/plan_step.erb +11 -0
  125. data/web/views/show.erb +54 -0
  126. metadata +250 -11
  127. data/examples/events.rb +0 -71
  128. data/examples/workflow.rb +0 -140
  129. data/lib/dynflow/bus.rb +0 -168
  130. data/lib/dynflow/dispatcher.rb +0 -36
  131. data/lib/dynflow/logger.rb +0 -34
  132. data/lib/dynflow/step.rb +0 -234
  133. data/test/bus_test.rb +0 -150
data/.gitignore CHANGED
@@ -1 +1,7 @@
1
1
  Gemfile.lock
2
+ *.swp
3
+ *.swn
4
+ *.swo
5
+ .bin
6
+ .bundle
7
+ .idea
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language:
2
+ - ruby
3
+
4
+ rvm:
5
+ - "1.9.3"
6
+ - "2.0.0"
7
+
8
+ script:
9
+ - bundle exec rake test
data/Gemfile CHANGED
@@ -5,13 +5,3 @@ gemspec
5
5
  group :development, :test do
6
6
  gem 'pry'
7
7
  end
8
-
9
- group :test do
10
- gem 'database_cleaner'
11
- end
12
-
13
- group :engine do
14
- gem "rails", "~> 3.2.8"
15
- gem "jquery-rails"
16
- gem "sqlite3"
17
- end
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2012 Pavel Pokorný
1
+ Copyright 2013 Ivan Nečas
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,25 +1,60 @@
1
- DYNamic workFLOW
2
- ================
1
+ ![Dynflow](doc/images/logo.png)
2
+ =======
3
+
4
+ Dynflow [DYN(amic work)FLOW] is a workflow engine
5
+ written in Ruby that allows to:
6
+
7
+ * keep track of the progress of running process
8
+ * run the code asynchronously
9
+ * resume the process when something goes wrong, skip some steps when needed
10
+ * detect independent parts and run them concurrently
11
+ * compose simple actions into more complex scenarios
12
+ * extend the workflows from third-party libraries
13
+ * keep consistency between local transactional database and
14
+ external services
15
+ * define the input/output interface between the building blocks (planned)
16
+ * define rollback for the workflow (planned)
17
+ * have multiple workers for distributing the load (planned)
18
+
19
+ Dynflow doesn't try to choose the best tool for the jobs, as the right
20
+ tool depends on the context. Instead, it provides interfaces for
21
+ persistence, transaction layer or executor implementation, giving you
22
+ the last word in choosing the right one (providing default
23
+ implementations as well).
24
+
25
+ * [Current status](#current-status)
26
+ * [How it works](#how-it-works)
27
+ * [Glossary](#glossary)
28
+ * [Related projects](#related-projects)
29
+
30
+ Current status
31
+ -------------
32
+
33
+ Dynflow has been under heavy development for several months to be able
34
+ to support the services orchestration in the
35
+ [Katello](http://katello.org) and [Foreman](http://theforeman.org/)
36
+ projects, getting to production-ready state in couple of weeks.
37
+
38
+ How it works
39
+ ------------
3
40
 
4
41
  In traditional workflow engines, you specify a static workflow and
5
42
  then run it with various inputs. Dynflow takes different approach.
6
-
7
43
  You specify the inputs and the workflow is generated on the fly. You
8
44
  can either specify the steps explicitly or subscribe one action to
9
45
  another. This is suitable for plugin architecture, where you can't
10
46
  write the whole process on one place.
11
47
 
12
48
  Dynflow doesn't differentiate between workflow and action. Instead,
13
- every action can populate another actions, effectively producing the
14
- resulting set of steps.
49
+ every action can populate another actions. This allows composing
50
+ more simpler workflows into a big one.
15
51
 
16
52
  The whole execution is done in three phases:
17
53
 
18
- 1. *Planning phase*
54
+ 1. *Plan phase*
19
55
 
20
- Construct the execution plan for the workflow. It's invoked by
21
- calling `trigger` on an action. Two mechanisms are used to get the set
22
- of actions to be executed:
56
+ Construct the execution plan for the workflow. Two mechanisms are
57
+ used to get the set of actions to be executed:
23
58
 
24
59
  a. explicit calls of `plan_action` methods in the `plan` method
25
60
 
@@ -29,7 +64,7 @@ The whole execution is done in three phases:
29
64
 
30
65
  The output of this phase is a set of actions and their inputs.
31
66
 
32
- 2. *Execution phase*
67
+ 2. *Run phase*
33
68
 
34
69
  The plan is being executed step by step, calling the run method of
35
70
  an action with corresponding input. The results of every action are
@@ -41,7 +76,7 @@ The output of this phase is a set of actions and their inputs.
41
76
  serialized therefore the workflow itself can be persisted. This makes
42
77
  it easy to recover from failed actions by rerunning it.
43
78
 
44
- 3. *Finalization phase*
79
+ 3. *Finalize phase*
45
80
 
46
81
  Take the results from the execution phase and perform some additional
47
82
  tasks. This is suitable for example for recording the results into
@@ -91,45 +126,26 @@ class Action < Dynflow::Action
91
126
  plan_action SubAction, object_1
92
127
  # we can specify, where in the workflow this action should be
93
128
  # placed, as well as prepare the input.
94
- plan_self {'id' => object_2.id, 'name' => object_2.name}
129
+ plan_self { id: object_2.id, name: object_2.name}
95
130
  end
96
131
 
97
132
  # OPTIONAL: run the execution part of this action. Transform the
98
133
  # data from +input+ to +output+. When not specified, the action is
99
134
  # not used in the execution phase.
100
135
  def run
101
- output['uuid'] = "#{input['name']}-#{input['id']}"
136
+ output[:uuid] = "#{input[:name]}-#{input[:id]}"
102
137
  end
103
138
 
104
139
  # OPTIONAL: finalize the action after the execution phase finishes.
105
140
  # in the +input+ and +output+ attributes are available the data from
106
141
  # execution phase. in the +outputs+ argument, all the execution
107
142
  # phase actions are available, each providing its input and output.
108
- def finalize(outputs)
109
- puts output['uuid']
143
+ def finalize
144
+ puts output[:uuid]
110
145
  end
111
146
  end
112
147
  ```
113
148
 
114
- One can generate the execution plan for an action without actually
115
- running it:
116
-
117
- ```ruby
118
- pp Publish.plan(short_article).actions
119
- # the expanded workflow is:
120
- # [
121
- # Publish: {"title"=>"Short", "body"=>"Short"} ~> {},
122
- # Review: {"title"=>"Short", "body"=>"Short"} ~> {},
123
- # Print: {"title"=>"Short", "body"=>"Short", "color"=>false} ~> {}
124
- # ]
125
- ```
126
-
127
- Therefore it's suitable for the plan methods to not have any side
128
- effects (except of database writes that can be roll-backed)
129
-
130
- In the finalization phase, `finalize` method is called on every action
131
- if defined. The order is the same as in the execution plan.
132
-
133
149
  Every action should be as atomic as possible, providing better
134
150
  granularity when manipulating the process. Since every action can be
135
151
  subscribed by another one, adding new behaviour to an existing
@@ -140,12 +156,58 @@ that other developers can use when extending the workflows.
140
156
 
141
157
  See the examples directory for more complete examples.
142
158
 
159
+ Glossary
160
+ --------
161
+
162
+ * **action** - building block for the workflows: a Ruby class
163
+ inherited from `Dynflow::Action`. Defines code to be run in
164
+ plan/run/finalize phase. It has defined input and output data.
165
+ * **execution plan** - definition of the workflow: product of the plan
166
+ phase
167
+ * **trigger an action** - entering the plan phase, starting with the
168
+ `plan` method of the action. The execution follows immediately.
169
+ * **plan_self** - converts the arguments of the `plan` method into
170
+ action input, that can be accessed from the `run`/`finalize`
171
+ phase.
172
+ * **plan_action** - includes another action into the workflow, passing
173
+ the arguments into the `plan` method of the action
174
+ * **step** - execution unit of the action. It represents the action in
175
+ specific phase (plan step, run step, finalize step).
176
+ * **flow** - definition of the run/finalize phase, holding the
177
+ information about steps that can run concurrently/in sequence.
178
+ Part of execution plan.
179
+ * **executor** - service that executes the run and finalize flows
180
+ based on the execution plan. It can run in the same process as the
181
+ plan phase or in different process (using the remote executor)
182
+ * **world** - the universe where the Dynflow runs the code: it holds
183
+ all needed configuration.
184
+
185
+ Related projects
186
+ ----------------
187
+
188
+ * [Foreman](http://theforeman.org) - lifecycle management tool for
189
+ physical and virtual servers
190
+
191
+ * [Katello](http://katello.org) - content management plugin for
192
+ Foreman: integrates couple of REST services for managing the
193
+ software updates in the infrastructure.
194
+
195
+ * [Foreman-tasks](https://github.com/iNecas/foreman-tasks) - Foreman
196
+ plugin providing the tasks management with Dynflow on the back-end
197
+
198
+ * [Dyntask](https://github.com/iNecas/dyntask) - generic Rails engine
199
+ providing the tasks management features with Dynflow on the back-end
200
+
201
+ * [Sysflow](https://github.com/iNecas/sysflow) - set of reusable tools
202
+ for running system tasks with Dynflow, comes with simple Web-UI for
203
+ testing it
204
+
143
205
  License
144
206
  -------
145
207
 
146
208
  MIT
147
209
 
148
- Author
149
- ------
210
+ Authors
211
+ -------
150
212
 
151
- Ivan Nečas
213
+ Ivan Nečas, Petr Chalupa
data/Rakefile CHANGED
@@ -1,15 +1,11 @@
1
1
  require 'rake/testtask'
2
2
  require 'fileutils'
3
3
 
4
- desc "Generic tests"
5
4
  Rake::TestTask.new do |t|
6
5
  t.libs << 'lib' << 'test'
7
6
  t.test_files = FileList['test/*_test.rb']
8
7
  t.verbose = true
9
8
  end
10
9
 
11
- namespace :test do
12
- desc "All tests"
13
- task :all => [:test] do
14
- end
15
- end
10
+ desc Rake::Task['test'].comment
11
+ task :default => :test
Binary file
data/dynflow.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.homepage = "http://github.com/iNecas/dynflow"
11
11
  s.summary = "DYNamic workFLOW engine"
12
12
  s.description = "Generate and executed workflows dynamically based "+
13
- "on input data and leave it open for others to jump into it as well"
13
+ "on input data and leave it open for others to jump into it as well"
14
14
 
15
15
  s.files = `git ls-files`.split("\n")
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -19,5 +19,14 @@ Gem::Specification.new do |s|
19
19
  s.add_dependency "activesupport"
20
20
  s.add_dependency "multi_json"
21
21
  s.add_dependency "apipie-params"
22
+ s.add_dependency "algebrick", '~> 0.4.0'
23
+ s.add_dependency "uuidtools"
24
+
25
+ s.add_development_dependency "rack-test"
22
26
  s.add_development_dependency "minitest"
27
+ s.add_development_dependency "minitest-reporters"
28
+ s.add_development_dependency "activerecord"
29
+ s.add_development_dependency "sequel"
30
+ s.add_development_dependency "sqlite3"
31
+ s.add_development_dependency "sinatra"
23
32
  end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root_path = File.expand_path(File.join(File.dirname(__FILE__), '..'))
4
+ dynflow_path = File.join(root_path, 'lib')
5
+ $LOAD_PATH << dynflow_path unless $LOAD_PATH.include? dynflow_path
6
+
7
+ require 'dynflow'
8
+ require 'tmpdir'
9
+
10
+ socket_path = File.join(Dir.tmpdir, 'dynflow_socket')
11
+ persistence_adapter = Dynflow::PersistenceAdapters::Sequel.new ARGV[0] || 'sqlite://db.sqlite'
12
+
13
+ world = Dynflow::SimpleWorld.new do |world|
14
+ { persistence_adapter: persistence_adapter,
15
+ executor: Dynflow::Executors::RemoteViaSocket.new(world, socket_path) }
16
+ end
17
+
18
+ load File.join(root_path, 'test', 'code_workflow_example.rb')
19
+
20
+ loop do
21
+ world.trigger Dynflow::CodeWorkflowExample::Slow, 1
22
+ sleep 0.5
23
+ p 'tick'
24
+ end
@@ -0,0 +1,121 @@
1
+ # Simple example on how Dynflow could be used for simple infrastructure orchestration
2
+
3
+ module Orchestrate
4
+
5
+ class CreateInfrastructure < Dynflow::Action
6
+
7
+ def plan
8
+ sequence do
9
+ concurrence do
10
+ plan_action(CreateMachine, 'host1', 'db')
11
+ plan_action(CreateMachine, 'host2', 'storage')
12
+ end
13
+ plan_action(CreateMachine,
14
+ 'host3',
15
+ 'web_server',
16
+ :db_machine => 'host1',
17
+ :storage_machine => 'host2')
18
+ end
19
+ sleep 2
20
+ end
21
+ end
22
+
23
+ class CreateMachine < Dynflow::Action
24
+
25
+ def plan(name, profile, config_options = {})
26
+ prepare_disk = plan_action(PrepareDisk, 'name' => name)
27
+ create_vm = plan_action(CreateVM,
28
+ :name => name,
29
+ :disk => prepare_disk.output['path'])
30
+ plan_action(AddIPtoHosts, :name => name, :ip => create_vm.output[:ip])
31
+ plan_action(ConfigureMachine,
32
+ :ip => create_vm.output[:ip],
33
+ :profile => profile,
34
+ :config_options => config_options)
35
+ plan_self(:name => name)
36
+ end
37
+
38
+ def finalize
39
+ puts "We've create a machine #{input[:name]}"
40
+ end
41
+
42
+ end
43
+
44
+ class PrepareDisk < Dynflow::Action
45
+
46
+ input_format do
47
+ param :name
48
+ end
49
+
50
+ output_format do
51
+ param :path
52
+ end
53
+
54
+ def run
55
+ sleep(rand(5))
56
+ output[:path] = "/var/images/#{input[:name]}.img"
57
+ end
58
+
59
+ end
60
+
61
+ class CreateVM < Dynflow::Action
62
+
63
+ input_format do
64
+ param :name
65
+ param :disk
66
+ end
67
+
68
+ output_format do
69
+ param :ip
70
+ end
71
+
72
+ def run
73
+ sleep(rand(5))
74
+ output[:ip] = "192.168.100.#{rand(256)}"
75
+ end
76
+
77
+ end
78
+
79
+ class AddIPtoHosts < Dynflow::Action
80
+
81
+ input_format do
82
+ param :ip
83
+ end
84
+
85
+ def run
86
+ sleep(rand(5))
87
+ end
88
+
89
+ end
90
+
91
+ class ConfigureMachine < Dynflow::Action
92
+
93
+ input_format do
94
+ param :ip
95
+ param :profile
96
+ param :config_options
97
+ end
98
+
99
+ def run
100
+ # for demonstration of resuming after error
101
+ if Orchestrate.should_fail?
102
+ Orchestrate.should_pass!
103
+ raise "temporary unavailabe"
104
+ end
105
+
106
+ sleep(rand(5))
107
+ end
108
+
109
+ end
110
+
111
+
112
+ # for simulation of the execution failing for the first time
113
+ def self.should_fail?
114
+ ! @should_pass
115
+ end
116
+
117
+ def self.should_pass!
118
+ @should_pass = true
119
+ end
120
+
121
+ end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root_path = File.expand_path(File.join(File.dirname(__FILE__), '..'))
4
+ dynflow_path = File.join(root_path, 'lib')
5
+ $LOAD_PATH << dynflow_path unless $LOAD_PATH.include? dynflow_path
6
+
7
+ require 'dynflow'
8
+ require 'tmpdir'
9
+
10
+ socket = File.join(Dir.tmpdir, 'dynflow_socket')
11
+ persistence_adapter = Dynflow::PersistenceAdapters::Sequel.new ARGV[0] || 'sqlite://db.sqlite'
12
+ world = Dynflow::SimpleWorld.new persistence_adapter: persistence_adapter
13
+ listener = Dynflow::Listeners::Socket.new world, socket
14
+
15
+ load File.join(root_path, 'test', 'code_workflow_example.rb')
16
+
17
+ Dynflow::Daemon.new(listener, world).run