Skip to content

Commit

Permalink
Better organization of dynflow-related stuff
Browse files Browse the repository at this point in the history
Besides better structure, it also makes sure the world initialization
happens after all engines were able to influence the dynflow
configuration.

From now on, to specify that another engine requires dynflow runtime,
it should call `ForemanTasks.dyntask.require!` instead
of `ForemanTasks.dyntask.initialize`.
  • Loading branch information
iNecas committed Jan 3, 2014
1 parent 6545881 commit 411122a
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 77 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ it would be:

```ruby
initializer "your_engine.dynflow_initialize" do |app|
ForemanTasks.dynflow_initialize
ForemanTasks.dynflow.require!
end
```

Expand Down
2 changes: 1 addition & 1 deletion app/models/foreman_tasks/task/dynflow_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def update_progress
end

def execution_plan
@execution_plan ||= ForemanTasks.world.persistence.load_execution_plan(external_id)
@execution_plan ||= ForemanTasks.dynflow.world.persistence.load_execution_plan(external_id)
end

def main_action
Expand Down
16 changes: 3 additions & 13 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require 'dynflow/web_console'

Foreman::Application.routes.draw do
namespace :foreman_tasks do
resources :tasks, :only => [:index, :show] do
Expand All @@ -14,17 +12,9 @@
end
end

if ForemanTasks.dynflow_initialized?
dynflow_console = Dynflow::WebConsole.setup do
before do
# NG_TODO: propper authentication
User.current = User.first
end

set(:world) { ForemanTasks.world }
end

mount dynflow_console => "/dynflow"
if ForemanTasks.dynflow.initialized?
require 'dynflow/web_console'
mount ForemanTasks.dynflow.web_console => "/dynflow"
end
end
end
55 changes: 4 additions & 51 deletions lib/foreman_tasks.rb
Original file line number Diff line number Diff line change
@@ -1,67 +1,20 @@
require 'foreman_tasks/version'
require 'foreman_tasks/engine'
require 'foreman_tasks/dynflow_configuration'
require 'foreman_tasks/dynflow_persistence'
require 'foreman_tasks/dynflow'

module ForemanTasks

def self.dynflow_initialized?
!@world.nil?
end

def self.dynflow_initialize
return @world if @world
dynflow_configuration.initialize_world.tap do |world|
@world = world

ActionDispatch::Reloader.to_prepare do
ForemanTasks.eager_load!
world.reload!
end

at_exit { world.terminate.wait }

# for now, we can check the consistency only when there
# is no remote executor. We should be able to check the consistency
# every time the new world is created when there is a register
# of executors
world.consistency_check unless dynflow_configuration.remote?
end
end

def self.dynflow_configuration
@configuration ||= ForemanTasks::DynflowConfiguration.new
end

def self.world
if @world
return @world
else
raise "The Dynflow world was not initialized yet. "\
"If your plugin uses it, make sure to call ForemanTasks.dynflow_initialize "\
"in after_initialize block"
end
def self.dynflow
@dynflow ||= ForemanTasks::Dynflow.new
end

def self.trigger(action, *args, &block)
world.trigger action, *args, &block
dynflow.world.trigger action, *args, &block
end

def self.async_task(action, *args, &block)
run = trigger(action, *args, &block)
ForemanTasks::Task::DynflowTask.find_by_external_id(run.id)
end

def self.eager_load_paths
@eager_load_paths ||= []
end

def self.eager_load!
eager_load_paths.each do |load_path|
# todo: does the reloading work now?x
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file
end
end
end
end
73 changes: 73 additions & 0 deletions lib/foreman_tasks/dynflow.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
module ForemanTasks
# Class for configuring and preparing the Dynflow runtime environment.
class Dynflow
require 'foreman_tasks/dynflow/configuration'
require 'foreman_tasks/dynflow/persistence'

attr_reader :config

def initialize
@config = ForemanTasks::Dynflow::Configuration.new
@required = false
end

# call this method if your engine uses Dynflow
def require!
@required = true
end

def initialized?
!@world.nil?
end

def initialize!
return unless @required
return @world if @world
config.initialize_world.tap do |world|
@world = world

ActionDispatch::Reloader.to_prepare do
ForemanTasks.dynflow.eager_load_actions!
world.reload!
end

at_exit { world.terminate.wait }

# for now, we can check the consistency only when there
# is no remote executor. We should be able to check the consistency
# every time the new world is created when there is a register
# of executors
world.consistency_check unless config.remote?
end
end

def world
if @world
return @world
else
raise "The Dynflow world was not initialized yet. "\
"If your plugin uses it, make sure to call ForemanTasks.dynflow.require! "\
"in some initializer"
end
end

def web_console
::Dynflow::WebConsole.setup do
before do
# TODO: propper authentication
User.current = User.first
end

set(:world) { ForemanTasks.dynflow.world }
end
end

def eager_load_actions!
config.eager_load_paths.each do |load_path|
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module ForemanTasks
class DynflowConfiguration
class Dynflow::Configuration

# for logging action related info (such as exceptions raised in side
# the actions' methods
Expand Down Expand Up @@ -27,17 +27,20 @@ class DynflowConfiguration
# based adapter, expecting ActiveRecord is used as ORM in the application
attr_accessor :transaction_adapter

attr_accessor :eager_load_paths

def initialize
self.action_logger = Rails.logger
self.dynflow_logger = Rails.logger
self.pool_size = 5
self.remote = false
self.remote_socket_path = File.join(Rails.root, "tmp", "dynflow_socket")
self.persistence_adapter = default_persistence_adapter
self.transaction_adapter = Dynflow::TransactionAdapters::ActiveRecord.new
self.transaction_adapter = ::Dynflow::TransactionAdapters::ActiveRecord.new
self.eager_load_paths = []
end

def initialize_world(world_class = Dynflow::World)
def initialize_world(world_class = ::Dynflow::World)
world_class.new(world_options) do |world|
{ executor: self.initialize_executor(world) }
end
Expand All @@ -47,16 +50,16 @@ def initialize_world(world_class = Dynflow::World)

# generates the options hash consumable by the Dynflow's world
def world_options
{ logger_adapter: Dynflow::LoggerAdapters::Delegator.new(action_logger, dynflow_logger),
executor_class: Dynflow::Executors::Parallel, # TODO configurable Parallel or Remote
{ logger_adapter: ::Dynflow::LoggerAdapters::Delegator.new(action_logger, dynflow_logger),
executor_class: ::Dynflow::Executors::Parallel, # TODO configurable Parallel or Remote
pool_size: 5,
persistence_adapter: persistence_adapter,
transaction_adapter: transaction_adapter }
end


def default_persistence_adapter
ForemanTasks::DynflowPersistence.new(default_sequel_adatper_options)
ForemanTasks::Dynflow::Persistence.new(default_sequel_adatper_options)
end

def default_sequel_adatper_options
Expand All @@ -68,9 +71,9 @@ def default_sequel_adatper_options

def initialize_executor(world)
if self.remote?
Dynflow::Executors::RemoteViaSocket.new(world, self.remote_socket_path)
::Dynflow::Executors::RemoteViaSocket.new(world, self.remote_socket_path)
else
Dynflow::Executors::Parallel.new(world, self.pool_size)
::Dynflow::Executors::Parallel.new(world, self.pool_size)
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module ForemanTasks
# in the Task model. This is probably a temporary solution and
# Dynflow will probably get more events-based API but it should be enought
# for start, until the requiements on the API are clear enough.
class DynflowPersistence < Dynflow::PersistenceAdapters::Sequel
class Dynflow::Persistence < ::Dynflow::PersistenceAdapters::Sequel

def save_execution_plan(execution_plan_id, value)
super.tap do
Expand Down
8 changes: 6 additions & 2 deletions lib/foreman_tasks/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Engine < ::Rails::Engine


initializer "foreman_tasks.register_paths" do |app|
ForemanTasks.eager_load_paths.concat(%W[#{ForemanTasks::Engine.root}/app/lib/actions])
ForemanTasks.dynflow.config.eager_load_paths.concat(%W[#{ForemanTasks::Engine.root}/app/lib/actions])
end

initializer "foreman_tasks.load_app_instance_data" do |app|
Expand All @@ -23,7 +23,7 @@ class Engine < ::Rails::Engine
# to enable async Foreman operations using Dynflow
if ENV['FOREMAN_TASKS_MONKEYS'] == 'true'
initializer "foreman_tasks.dynflow_initialize" do |app|
ForemanTasks.dynflow_initialize
ForemanTasks.dynflow.require!
end

config.to_prepare do
Expand All @@ -32,6 +32,10 @@ class Engine < ::Rails::Engine
::Architecture.send :include, ForemanTasks::Concerns::ArchitectureActionSubject
end
end

config.after_initialize do
ForemanTasks.dynflow.initialize!
end
end

def self.table_name_prefix
Expand Down

0 comments on commit 411122a

Please sign in to comment.