Module: AgentDispatcher

Included in:
AgentUtils::AgentBase
Defined in:
lib/agentdispatcher.rb

Overview

Complex command dispatcher mixin / Application micro-framework

Simplifies creation of configurable objects which can react on messages/events while using OO approach. They can be easily executed from command line. The micro-framework has lots of features. Therefore an example first:

Example Usage

agent.rb:

class Agent
     include AgentDispatcher
     @AllowedCommands = %w(start stop)
     def on_run *args 
         # do some job
     end
     def on_stop *args 
         # do some job
     end
     ...
end

class AgentB < Agent
     @DefaultCfg = {:log_path=>'/tmp'}
     @AllowedCommands = %w(start run stop)
     upMethod :initBussines
     def initBussines
         puts "post creation placeholder"
     end
     downMethod :closeBussines
     def closeBussines
         puts "pre-shutdown placeholder"
     end
     def on_run *args 
         # do some job
     end
     ...
end
if __FILE__ == $0
    AgentB::Dispatch *ARGV
end

There are several options how to dispatch events to the ‘agent’ (programatically)

Agent::Dispatch *ARGV
AgentB::Dispatch 'agent1', 'run', 'param1', 'param2'
Agent::Dispatch 'start'
Agent::DispatchString '--config cfgfile1,cfgfile2 agentID start'
Agent.new(...).dispatch *ARGV

The purpose of ARGV variants is of course to call the ‘agent’ right away from the command line, e.g.:

agent.rb --config cfgfile1,cfgfile2 agentID start
agent.rb --help

Feature Documentation

  • dispatching commands (+id, arguments, configuration)

  • defintion of accepted commands @AllowedCommands = %w(start stop)

  • command handler method in format on_#{command in lowercase}<tt> (e.g. <tt>run -> <tt>on_run<tt>)

  • dispatching from: command-line string, ARGV, Hash

  • the agents object can used conventional inheritance to override/add new behavior.

  • objects may have their own constructors (the class method Dispatch uses default constructor)

  • injection of business constructors/desctructors

    • upMethod aMethodName

    • downMethod aMethodName

  • autogeneration of command-line help

  • (TODO: in future support for any methods by injections)

Configuration

  • hierarchical configuration (the final configuration is constructed by overlaying several sources)

  • default config can be defined in class variable @DefaultCfg = {:log_path=>'/tmp'}

  • loaded from file; specified in option :config either by path (ends with .yml) or by name (the file is loaded from #{AGENTS_ROOT}/config/#{name}.yml)

  • multiple configuration files can be passed :config=>'cfg1,cfg2', precedence in the given order

  • the configuration can be given by arguments

  • precedence of configuration overlaying defaut < files < arguments

Logging

  • @log instance variable is created, can be overriden in object constructor

  • default path is #{AGENTS_ROOT}/tmp/log/#{@id}.log

  • the path can be modified by setting :log_path option

Process Management

  • a PID file is generated while the script is running

  • generated in #{AGENTS_ROOT}/var/run/#{@id}.pid

  • the path can be modified by setting :pid_path option

  • passing :nopid option supresses genereation of pid file

  • process does not start if a pid file already exists. Force execution by passing :forcepid option

Comandline format Usage: #@agentClass [CONFIG] [ID] [COMMAND] [ARGS]

CONFIG     Any application specific configuration flags in the format --NAME VALUE[,VALUE]*
           Special flags: {help, id, config=[A,B,...],log_path, nopid, pid_path, quiet, cmd}
ID         Instance id of the agent (default: 'id-fied classname')
COMMAND    Command to execute [aplication soec. commands] (default: 'run')
ARGS       Space separated arguments (default:none)
  • Passing :help option makes the script to generate help intructions to the STDOUT

Author

Viktor Zigo, alephzarro.com, All rights reserved. Distributed under GNU GPL License (see LICENSE).

sponsored by 7inf.com

Defined Under Namespace

Modules: AgentDispatcherClassMethods

Constant Summary collapse

PID_PATH =
'var/run'
LOG_PATH =
'tmp/log'
AGENTS_ROOT =
(ENV['AGENTS_ROOT'] ||  '.' )

Instance Method Summary collapse

Instance Method Details

#dispatch(*argv) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/agentdispatcher.rb', line 110

def dispatch *argv
##        puts "AGENTS_ROOT: #{AGENTS_ROOT}, agentClass: #{self.class} allowedCmds: #{self.class.AllowedCommands}"
    #make validation customizable
    cfg = AgentUtils::ConfFactory.new(self.class).createFromArgv *argv
    id = cfg[:id]
    #TODO: forcepid

    #generate pid
    cfg[:pid_path] = File.join( AGENTS_ROOT, PID_PATH, "#{id}.pid") unless cfg[:pid_path]
    ProcTools::withPidFile(cfg[:pid_path], cfg) do
        initializeAgent cfg
        cmd = cfg[:cmd]
        if self.class.AllowedCommands().include? cmd 
            executeInjections :postInit
            begin
                self.send "on_#{cmd.downcase}", *cfg[:args]
            ensure
                executeInjections :preExit
            end
        else
            raise "Unknown command '#{cmd}', allowed commands are {#{self.class.AllowedCommands.join(',')}}"
        end    
    end
end

#dispatchString(aString) ⇒ Object

@AllowedCommands = []



106
107
108
# File 'lib/agentdispatcher.rb', line 106

def dispatchString aString
    dispatch *aString.split
end