github.com/TIBCOSoftware/flogo-lib@v0.5.9/engine/engine.go (about)

     1  package engine
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"os/signal"
     8  	"runtime/debug"
     9  	"syscall"
    10  
    11  	"github.com/TIBCOSoftware/flogo-lib/app"
    12  	"github.com/TIBCOSoftware/flogo-lib/config"
    13  	"github.com/TIBCOSoftware/flogo-lib/core/action"
    14  	"github.com/TIBCOSoftware/flogo-lib/core/data"
    15  	"github.com/TIBCOSoftware/flogo-lib/core/trigger"
    16  	"github.com/TIBCOSoftware/flogo-lib/engine/runner"
    17  	"github.com/TIBCOSoftware/flogo-lib/logger"
    18  	"github.com/TIBCOSoftware/flogo-lib/util"
    19  	"github.com/TIBCOSoftware/flogo-lib/util/managed"
    20  	"sync"
    21  	"github.com/TIBCOSoftware/flogo-lib/engine/channels"
    22  )
    23  
    24  var managedServices []managed.Managed
    25  var lock = &sync.Mutex{}
    26  
    27  // Interface for the engine behaviour
    28  type Engine interface {
    29  	// Init initialize the engine
    30  	Init(directRunner bool) error
    31  
    32  	// Start starts the engine
    33  	Start() error
    34  
    35  	// Stop stop the engine
    36  	Stop() error
    37  
    38  	// TriggerInfos get info for the triggers
    39  	TriggerInfos() []*managed.Info
    40  }
    41  
    42  func LifeCycle(managedEntity managed.Managed)  {
    43  	defer lock.Unlock()
    44  	lock.Lock()
    45  	managedServices = append(managedServices, managedEntity)
    46  }
    47  
    48  
    49  // engineImpl is the type for the Default Engine Implementation
    50  type engineImpl struct {
    51  	app            *app.Config
    52  	initialized    bool
    53  	logLevel       string
    54  	actionRunner   action.Runner
    55  	serviceManager *util.ServiceManager
    56  
    57  	triggers     map[string]trigger.Trigger
    58  	triggerInfos map[string]*managed.Info
    59  }
    60  
    61  // New creates a new Engine
    62  func New(appCfg *app.Config) (Engine, error) {
    63  	// App is required
    64  	if appCfg == nil {
    65  		return nil, errors.New("no App configuration provided")
    66  	}
    67  	// Name is required
    68  	if len(appCfg.Name) == 0 {
    69  		return nil, errors.New("no App name provided")
    70  	}
    71  	// Version is required
    72  	if len(appCfg.Version) == 0 {
    73  		return nil, errors.New("no App version provided")
    74  	}
    75  
    76  	//fix up app configuration if it is older
    77  	//app.FixUpApp(appCfg)
    78  
    79  	logLevel := config.GetLogLevel()
    80  
    81  	return &engineImpl{app: appCfg, serviceManager: util.GetDefaultServiceManager(), logLevel: logLevel}, nil
    82  }
    83  
    84  func (e *engineImpl) Init(directRunner bool) error {
    85  
    86  	if !e.initialized {
    87  		e.initialized = true
    88  
    89  		if directRunner {
    90  			e.actionRunner = runner.NewDirect()
    91  		} else {
    92  			e.actionRunner = runner.NewPooled(NewPooledRunnerConfig())
    93  		}
    94  
    95  		propProvider := app.GetPropertyProvider()
    96  		// Initialize the properties
    97  		props, err := app.GetProperties(e.app.Properties)
    98  		if err != nil {
    99  			return err
   100  		}
   101  		propProvider.SetProperties(props)
   102  		data.SetPropertyProvider(propProvider)
   103  
   104  		actionFactories := action.Factories()
   105  		for _, factory := range actionFactories {
   106  			if initializable, ok := factory.(managed.Initializable); ok {
   107  
   108  				if err := initializable.Init(); err != nil {
   109  					return err
   110  				}
   111  			}
   112  		}
   113  
   114  		//add engine channels
   115  		channelDescriptors := e.app.Channels
   116  		if len(channelDescriptors) > 0 {
   117  			for _, descriptor := range channelDescriptors {
   118  				name, buffSize := channels.Decode(descriptor)
   119  
   120  				logger.Debugf("Creating Engine Channel '%s'", name)
   121  				channels.New(name, buffSize)
   122  			}
   123  		}
   124  
   125  		err = app.RegisterResources(e.app.Resources)
   126  		if err != nil {
   127  			return err
   128  		}
   129  
   130  		actions, err := app.CreateSharedActions(e.app.Actions)
   131  		if err != nil {
   132  			errorMsg := fmt.Sprintf("Error creating shared action instances - %s", err.Error())
   133  			logger.Error(errorMsg)
   134  			panic(errorMsg)
   135  		}
   136  
   137  		//todo add all actions to engine (will make cleanup easier)
   138  
   139  		triggers, err := app.CreateTriggers(e.app.Triggers, actions, e.actionRunner)
   140  		e.triggerInfos = make(map[string]*managed.Info)
   141  
   142  		if err != nil {
   143  			errorMsg := fmt.Sprintf("Error Creating trigger instances - %s", err.Error())
   144  			logger.Error(errorMsg)
   145  			panic(errorMsg)
   146  		}
   147  
   148  		e.triggers = triggers
   149  	}
   150  
   151  	return nil
   152  }
   153  
   154  //Start initializes and starts the Triggers and initializes the Actions
   155  func (e *engineImpl) Start() error {
   156  
   157  	logger.SetDefaultLogger("engine")
   158  
   159  	logger.Infof("Starting app [ %s ] with version [ %s ]", e.app.Name, e.app.Version)
   160  	logger.Info("Engine Starting...")
   161  
   162  	// Todo document RunnerType for engine configuration
   163  	runnerType := GetRunnerType()
   164  	err := e.Init(runnerType == "DIRECT")
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	logger.Info("Starting Services...")
   170  
   171  	actionRunner := e.actionRunner.(interface{})
   172  
   173  	if managedRunner, ok := actionRunner.(managed.Managed); ok {
   174  		managed.Start("ActionRunner Service", managedRunner)
   175  	}
   176  
   177  	err = e.serviceManager.Start()
   178  
   179  	if err != nil {
   180  		logger.Error("Error Starting Services - " + err.Error())
   181  	} else {
   182  		logger.Info("Started Services")
   183  	}
   184  
   185  	if len(managedServices) > 0 {
   186  		for _, mService := range managedServices {
   187  			err = mService.Start()
   188  			if err != nil {
   189  				logger.Error("Error Starting Services - " + err.Error())
   190  				//TODO Should we exit here?
   191  			}
   192  		}
   193  	}
   194  
   195  	// Start the triggers
   196  	logger.Info("Starting Triggers...")
   197  
   198  	var failed []string
   199  
   200  	for key, value := range e.triggers {
   201  		triggerInfo := &managed.Info{Name: key}
   202  		err := managed.Start(fmt.Sprintf("Trigger [ %s ]", key), value)
   203  		if err != nil {
   204  			logger.Infof("Trigger [%s] failed to start due to error [%s]", key, err.Error())
   205  			triggerInfo.Status = managed.StatusFailed
   206  			triggerInfo.Error = err
   207  			logger.Debugf("StackTrace: %s", debug.Stack())
   208  			if config.StopEngineOnError() {
   209  				logger.Debugf("{%s=true}. Stopping engine", config.ENV_STOP_ENGINE_ON_ERROR_KEY)
   210  				logger.Info("Stopped")
   211  				os.Exit(1)
   212  			}
   213  			failed = append(failed, key)
   214  		} else {
   215  			triggerInfo.Status = managed.StatusStarted
   216  			logger.Infof("Trigger [ %s ]: Started", key)
   217  			logger.Debugf("Trigger [ %s ] has ref [ %s ] and version [ %s ]", key, value.Metadata().ID, value.Metadata().Version)
   218  		}
   219  
   220  		e.triggerInfos[key] = triggerInfo
   221  	}
   222  
   223  	if len(failed) > 0 {
   224  		//remove failed trigger, we have no use for them
   225  		for _, triggerId := range failed {
   226  			delete(e.triggers, triggerId)
   227  		}
   228  	}
   229  
   230  	logger.Info("Triggers Started")
   231  
   232  	if channels.Count() > 0 {
   233  		logger.Info("Starting Engine Channels...")
   234  		channels.Start()
   235  		logger.Info("Engine Channels Started")
   236  	}
   237  
   238  	logger.Info("Engine Started")
   239  
   240  	return nil
   241  }
   242  
   243  func (e *engineImpl) Stop() error {
   244  	logger.Info("Engine Stopping...")
   245  
   246  	if channels.Count() > 0 {
   247  		logger.Info("Stopping Engine Channels...")
   248  		channels.Stop()
   249  		logger.Info("Engine Channels Stopped...")
   250  	}
   251  
   252  	logger.Info("Stopping Triggers...")
   253  
   254  	// Stop Triggers
   255  	for trgId, tgr := range e.triggers {
   256  		managed.Stop("Trigger [ "+trgId+" ]", tgr)
   257  		e.triggerInfos[trgId].Status = managed.StatusStopped
   258  	}
   259  
   260  	logger.Info("Triggers Stopped")
   261  
   262  	//TODO temporarily add services
   263  	logger.Info("Stopping Services...")
   264  
   265  	actionRunner := e.actionRunner.(interface{})
   266  
   267  	if managedRunner, ok := actionRunner.(managed.Managed); ok {
   268  		managed.Stop("ActionRunner", managedRunner)
   269  	}
   270  
   271  	err := e.serviceManager.Stop()
   272  
   273  	if err != nil {
   274  		logger.Error("Error Stopping Services - " + err.Error())
   275  	} else {
   276  		logger.Info("Stopped Services")
   277  	}
   278  
   279  	if len(managedServices) > 0 {
   280  		for _, mService := range managedServices {
   281  			err = mService.Stop()
   282  			if err != nil {
   283  				logger.Error("Error Stopping Services - " + err.Error())
   284  			}
   285  		}
   286  	}
   287  
   288  	logger.Info("Engine Stopped")
   289  	return nil
   290  }
   291  
   292  func (e *engineImpl) TriggerInfos() []*managed.Info {
   293  
   294  	infos := make([]*managed.Info, 0, len(e.triggerInfos))
   295  
   296  	for _, info := range e.triggerInfos {
   297  		infos = append(infos, info)
   298  	}
   299  
   300  	return infos
   301  }
   302  
   303  func RunEngine(e Engine) {
   304  
   305  	err := e.Start()
   306  
   307  	if err != nil {
   308  		fmt.Println("Error starting engine", err.Error())
   309  		os.Exit(1)
   310  	}
   311  
   312  	exitChan := setupSignalHandling()
   313  
   314  	code := <-exitChan
   315  
   316  	e.Stop()
   317  
   318  	os.Exit(code)
   319  }
   320  
   321  func setupSignalHandling() chan int {
   322  
   323  	signalChan := make(chan os.Signal, 1)
   324  	signal.Notify(signalChan,
   325  		syscall.SIGHUP,
   326  		syscall.SIGINT,
   327  		syscall.SIGTERM,
   328  		syscall.SIGQUIT)
   329  
   330  	exitChan := make(chan int)
   331  	go func() {
   332  		for {
   333  			s := <-signalChan
   334  			switch s {
   335  			// kill -SIGHUP
   336  			case syscall.SIGHUP:
   337  				exitChan <- 0
   338  				// kill -SIGINT/Ctrl+c
   339  			case syscall.SIGINT:
   340  				exitChan <- 0
   341  				// kill -SIGTERM
   342  			case syscall.SIGTERM:
   343  				exitChan <- 0
   344  				// kill -SIGQUIT
   345  			case syscall.SIGQUIT:
   346  				exitChan <- 0
   347  			default:
   348  				logger.Debug("Unknown signal.")
   349  				exitChan <- 1
   350  			}
   351  		}
   352  	}()
   353  
   354  	return exitChan
   355  }