Handling Components with Long Initialization Times (Aspire 2)

From wiki.searchtechnologies.com
Jump to: navigation, search

For Information on Aspire 3.1 Click Here

Introduction

Components that take a long time to initialize should use a background thread for performing this initialization. This is so that OSGi doesn't hang while waiting for your component to initialize.

The framework class, ComponentImpl (the base class for all components and pipeline stages) implements several methods to make it easier to handle background initialization threads. These methods handle startup initialization with a specific set of protocols:

The implications of the protocol:

  • Initialization must be completely clean – no exceptions.
  • If initialization has thrown an exception:
    • All jobs sent to process() will fail.
    • All other calls should fail (example: getConnection() to aspire-rdb should fail if initialization had previously failed).
  • All accesses to do work-type-things should block until initialization is complete.
    • There is no timeout (currently). Initialization could take a very long time (hours), and this is okay.
    • A global timeout parameter will be added at some point to settings.xml.
  • All initializations must complete – at some point.
  • All initializations should be interrupt-able.
    • Certainly on shutdown.
    • And possibly by the AspireApplication in response to an administrator command.
  • All threads blocked for the initialization should be interrupt-able, too.

What it looks like in the Admin Interface

If you use the methods below, your component will automatically report its initialization status on the admin interface with a message and a progress bar:

Initialization progress.png

If an exception error occurs during initialization, this will also be reported:

Initialization exception.png

(Clicking 'more' gives you the exception error traceback stack.)

Methods

The following methods are all specified on the ComponentImpl class (the base class for most Aspire Components).

To manage the background thread:

  • startBackgroundInitialization(Runnable runnableObj) - Establishes the locking mechanism and launches a thread to execute the runnable object in the background.
  • endBackgroundInitialization() – Called by the background thread when initialization is complete.
  • closeBackgroundInitialization() – Should be called in the component close() to shutdown the background initialization thread in case a close is requested before initialization is complete.
  • checkInitialized() – Checks initialization and blocks if initialization is not complete. Should be called in process() and any place where anyone needs to have a fully initialized component before real work can begin.
  • setInitializationException(Exception e) – Called by the background thread if there’s a fatal error during initialization.

To report status:

  • setMaxInitializationProgress(int maxValue) – To set a maximum value for the progress bar.
  • setCurInitializationProgress(int curValue) – To set the current initialization status value for the progress bar.
    • This should be called relatively frequently – i.e. once per second or so.
    • This method also checks to see if the thread has been interrupted (if, for example, the parent object has been closed), and then throws an exception error if so.
  • setInitializationMessage(String fmt, Object ... args) – Set a message which describes the initialization status.

Example Code

class MyStage extends StageImpl implements Runnable  // NOTE:  Implements Runnable
{
 
 @Override
 public void process(Job j) throws AspireException {
   checkInitialized();  // Blocks the job if the stage is not yet initialized
   
   // Note:  Use this method for any access which a requires a fully initialized component
   
   .
   .
   .
 }
 
 
 public void close() {
   .
   .
   .
   // Shuts down any background initialization thread
   closeBackgroundInitialization();
 }
 
 
 
 public void initialize(Element config) {
   .
   .
   .
   
   // Initializing locking mechanism and starts up the background thread
   startBackgroundInitialization(this);
 }
  
 
 
 @Override
 public void run() {
   try {
     setMaxInitializationProgress(/*set to appropriate value*/100);
     
     
     // Initialize the component here
     // use:
     //   setCurInitializationProgress() - to set the current progress bar setting
     //   setInitializationMessage() - to specify a message letting the admin user know what's going on
     .
     .
     .
   }
   catch(Exception e) {
     setInitializationException(e);
   }
   finally {
     endBackgroundInitialization();
   }
 }