Catching interrupt events from your application's service code was an error-prone, manual and inefficient task in previous versions of Symphony (3.2 and earlier).
For example, here is a C# Symphony service written for Symphony 3.2. It tries to catch and handle KILL events caused by killing a session. The sample code below first makes a temporary directory in onSessionEnter and the temporary directory is deleted at onSessionLeave.
When the session gets killed, the service attempts to delete the directory at onInvoke by catching the KILL event using the InterruptEvent object.
Failure to match up the WAIT_PERIOD above and the taskCleanupPeriod in the <Session> section of your application profile may cause the service to miss the session KILL event.Code:public override void OnInvoke(TaskContext taskContext) { try { do { InterruptEvent iEvent = serviceContext.LastInterruptEvent; if (iEvent.EventCode != InterruptEventCode.None) { // Terminate Decendant Processes and Remove Working Dir try { // Remove Working Dir here } catch {} if (iEvent.EventCode == InterruptEventCode.SessionSuspended) { // Some actions for session suspend } else { // Some actions for session kill } } } while (!se.WaitForExit(WAIT_PERIOD)); // Just rotate "while" several times } catch (StandardExecutorException e) { // Reaction for exception } catch (SoamException e) { // Reaction for exception } catch (Exception e) { // Reaction for exception } }
In previous versions of Symphony, you had to go through the hassle of manually setting taskCleanupPeriod to be always greater than the WAIT_PERIOD. Also, this way of polling for an event is not efficient.
For usability and efficiency reasons, Symphony 4.0 introduced onServiceInterrupt(), an event-based callback method. Inside the implementation of onServiceInterrupt, you can retrieve the last caught event through the method getLastInterruptEvent() in the ServiceContext class as shown in the sample service code below. The method will return the gracePeriod set as the taskCleanupPeriod in the application profile and you don't have to worry about the service prematurely exiting without doing the necessary operations.
You can find the complete sample code for onServiceInterrupt under %SOAM_HOME%/4.0/samples.Code:public override void OnServiceInterrupt(ServiceContext serviceContext) { //@@onInterrupt_GLOBAL@@ const string fname="onServiceInterrupt()"; m_serviceOutput.WriteLine(fname + ": enter"); // print interrupt information InterruptEvent eve = serviceContext.LastInterruptEvent; string eventString; switch(eve.EventCode) { case InterruptEventCode.TaskKilled: eventString = "TaskKilled"; break; case InterruptEventCode.TaskSuspended: eventString = "TaskSuspended"; break; default: eventString = "Unkown"; break; } m_serviceOutput.WriteLine("InterruptEvent = " + eventString + ", gracePeriod = " + eve.GracePeriod + "ms"); closeDB(fname); m_serviceOutput.WriteLine(fname + ": exit"); m_serviceOutput.WriteLine(); m_serviceOutput.Flush(); // close the stream m_serviceOutput.Close(); } // simulate connection to DB private void connectDB() { m_serviceOutput.WriteLine("connected to DB."); m_serviceOutput.Flush(); } // simulate some processing in DB with the given arguments private void processDB(int iter, int sleep) { //no-op } // simulate closing connection DB private void closeDB(string fname) { m_serviceOutput.WriteLine("CONNECTION TO DB CLOSED IN " + fname); m_serviceOutput.Flush(); } // simulate some intensive operation is happening. private void intensiveOp(int iter, int sleepTime) { // supposedly intensive operation m_result += iter + sleepTime; Thread.Sleep(sleepTime * 1000); } }


LinkBack URL
About LinkBacks
Reply With Quote