Re: sfStart() timeout

Steve Loughran <[email protected]> Wed, 06 Dec 2006 12:23:31 +0000
Newsgroups gmane.comp.java.smartfrog.user
Message-ID <[email protected]>
Dominik Pospisil wrote:
> Hello there!
> 
> I am trying to write a smartfrog component which's start can take ralativelly 
> long time (even minutes). The problem is following. Should I run component 
> startup in a new thread and exit sfStart() immidiatelly or should I block 
> sfStart() until component starts up?
> 
> According to docs, when a compoent leave sfStart(), SF assumes that component 
> is running and ready. But If I block sfStart() until component is ready, I 
> receive liveness check errors.
> 
> If I do not block sfStart(), dependant components will fail to start, because 
> component is not ready yet.
> 
> Did I missed something? Is there another solution than increasing liveness 
> checking period?
> 

Dominik,

I've been discussing this problem with my colleagues.

You should certainly start slow-starting actions in their own thread, 
one that begins in sfStart() and which sfTerminateWith() 
interrupts/halts. The big problem here is low starting operations as
  (a) the sfPing() calls on that component can start early on, before 
the thread has finished starting the database, Xen image, or the like.
  (b) You need other things to block until the slow starting thing is 
ready.

For (a), I'm thinking of adding a SlowStart {} component which can take 
a timeout alongside the action component, that being what is deployed

bigMySQL extends SlowStart {
  timeout 600000;
  action extends Database;
}

This component would not pass down liveness tests to the deployed action 
until the timeout had passed. It would still check every time it got 
pinged, but would ignore failure. The moment that the liveness did start 
to succeed, the component would switch state into 'live' mode, after 
which point case the ping operations would always be passed down.

(b) is the other problem. I've actually been prototyping two things last 
week

conditons
======
a model of Conditions. Any component that implements the Condition 
interface, with its boolean evaluate() operation, can become a 
condition, and get deployed under a condition container.

the first containers are


//something to test
  If {
    condition  {}
    then {}
    else {}
}


//something to block waiting for a state change
WaitFor  {
    timeout TBD;
    condition  {}
    then {}
    else {}
}

//something to fail if the condition is not met in a time period. It 
will terminate afterwards so
//can be used in a sequence

FailingWaitFor extends WaitFor {
   message "Timed out";

   then extends Terminator {
     description PARENT:message;
     selftype Terminator:ABNORMAL;
   }
}

//something to evaluate a condition every liveness test
LivenessTest {
	condition {}
}


I've also got some basic conditions, including the boolean and/or/not.


Databases.
======

The other thing I've been doing is adding the tests for the database 
components, which use JDBC to talk to a database. We can connect to a 
database, and issue SQL commands. I havent yet done the fetching of 
results back into smartfrog yet, but something is possible there given a 
good use case.

What I have done is written a ConnectionOpen condition, which tries to 
open the database connection every evaluate(). this can be used to check 
that you can connect to a database over the wire, and so block until 
something is there:

ConnectionOpenTest extends TestCompound {

     description "This test blocks until a connection is open, and fails 
if this is not possible";

     action extends TestDB {
     }

     tests extends Sequence {

         wait extends FailingWaitFor {
           condition extends ConnectionOpen {
             database LAZY action;
           }
          interval 200;
          timeout 2000;
         }

     }
   }

This test will deploy the action component, then run the test sequence, 
which is set up to block until the db connection is open.

For MySQL, I've added a specific condition that issues a mysql ping command:

IsMysqlLive extends ConnectionOpens {
   sfClass "org.smartfrog.services.database.mysql.IsMysqlLive";
}

We could also have a SelectCondition () that issues a select call. If we 
add the ability to declare the result size or its string value, you 
could even block waiting for the database to be populated:

isDatabaseReady extends SelectCondition {
    database LAZY TestDB;
    command "SELECT COUNT(*) FROM EVENTS";
    equals "500";
}


How would all this suit you? Provided I get the tests finished and 
cruise control is happy, we could cut a leading-edge developer release 
at the end of the week. These arent as rigorously tested as the 
production releases, being a snapshot of what we are using, but most of 
the single-host functional tests all run on the continuous integration 
server, so its only the cross-machine tests that get skipped.

-steve



-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV