UniVerse

Controlling PHANTOM tasks using process locks

  • 1.  Controlling PHANTOM tasks using process locks

    Posted 18 days ago
      |   view attached
    If you have become used to stopping PHANTOM processes by killing them or editing a controlling record in a file, there is a much more elegant method available using the often under-recognised method of process locks.

    For example, if we choose lock 1 to signify that a job is already running and lock 2 to instruct a job to terminate, then the code below can be used to ensure that one - and only one - instance of the HANTOM is permitted to run at any one time:

    * Sample code snippet:- PHANTOM job start * * Set the PHANTOM job name * PHANTOM_JOB='WEEKLY_INVOICES_EMEA' * * Designate the locks to be used for this handshake * RUNNING_LOCK=1 ; * the lock number used by the PHANTOM when it is running * * check if the PHANTOM is running by attempting to set the process lock * that it would own if it were already running. * LOCK RUNNING_LOCK THEN * * The controlled job is not running - OK to start it * first release the lock we just set to check if it was already running. * UNLOCK RUNNING_LOCK * * now launch the PHANTOM * EXECUTE 'PHANTOM ':PHANTOM_JOB PRINT 'PHANTOM ':PHANTOM_JOB:' launched @ ':TIMEDATE() END ELSE * * already running - do not allow a second copy to run * PRINT PHANTOM_JOB:' is already started @ ':TIMEDATE() END​


    As can be seen,  if Process Lock 1 is set then the PHANTOM is already running, and we only permit one instance of the PHANTOM to run. If however the PHANTOM is not already running then once launched it would set Process Lock 1 to indicate that it is now running.


    Similar code using process lock 2 can now be used to request that the PHANTOM terminate in a controlled fashion. As the PHANTOM job being used as an example may be either busy performing its designated task or sleeping waiting for a set time to elapse, we have added a loop/retry with a brief pause between each attempt.

    * Sample code snippet:- PHANTOM job termination * * Set the PHANTOM job name * PHANTOM_JOB='WEEKLY_INVOICES_EMEA' * * Designate the locks to be used for this handshake * RUNNING_LOCK=1; * the lock number used by the job being controlled when it is running STOPPING_LOCK=2; * the lock number used to signal the job to stop * ALL_DONE=0 * * check if the job is running * LOCK RUNNING_LOCK THEN * * The running lock could be obtained, so the job is not running and * there is nothing to do. * UNLOCK RUNNING_LOCK PRINT PHANTOM_JOB:' not running @ ':TIMEDATE() * END ELSE * * The job is running, so signal it to stop * LOCK STOPPING_LOCK THEN * * iterate - looking for the RUNNING_LOCK to be released when * the job terminates. * MONITOR_STOPPED=0 CHECK_INTERVAL=2; * interval between checks of the process status CHECK_ITERATIONS=30; * number of times to check at the selected interval ITERATION_PASS=0 LOOP * * Is the job still running? * LOCK RUNNING_LOCK THEN * * No - it is not running * unlock the two locks we are using and exit gracefully. * UNLOCK RUNNING_LOCK UNLOCK STOPPING_LOCK ALL_DONE=1 IF ITERATION_PASS #0 THEN PRINT PRINT PHANTOM_JOB:' stopped @ ':TIMEDATE() END ELSE * * Still running - wait a little longer * ITERATION_PASS +=1 * * Prettification - give a ticking row of dots as we wait * IF ITERATION_PASS=1 THEN PRINT 'Waiting .': END ELSE PRINT '.': END IF ITERATION_PASS > CHECK_ITERATIONS THEN * * Number of attempts to stop the job exceeded - abandon the attempt. * ALL_DONE=2 PRINT; PRINT 'Stop of ':PHANTOM_JOB:' failed @ ':TIMEDATE() END END UNTIL ALL_DONE#0 DO * * sleep until the next iteration * SLEEP CHECK_INTERVAL REPEAT PRINT END ELSE * * STOPPING_LOCK already set - can't be used by two processe at the same time * PRINT 'Unable to set lock ':STOPPING_LOCK:' already set/in use @ ':TIMEDATE() END END


    Following on from the two controlling programs illustrated above, it now follows that the job being controlled will use the same locks in its overall control structures. Lock 1 indicating that the job is already running, and lock 2 indicating that the job has been requested to stop:

    * Sammple code snippet: job being controlled * PHANTOM_JOB='WEEKLY_INVOICES_EMEA' * * Designate the locks to be used for this handshake * RUNNING_LOCK=1; * the lock number used by the job when it is running STOPPING_LOCK=2; * the lock number used to signal the job to stop * * Is the job already running? * LOCK RUNNING_LOCK THEN * * Not already running - so OK to run as long as it has not * already been asked to stop. So is STOPPING_LOCK set? * LOCK STOPPING_LOCK THEN * * No - so still OK to run. * UNLOCK STOPPING_LOCK END ELSE UNLOCK RUNNING_LOCK PRINT PHANTOM_JOB:' under orders to stop - exiting @ ':TIMEDATE() STOP END END ELSE * * already running - exit * PRINT PHANTOM_JOB:' already running, stopping @ ':TIMEDATE() STOP END * * * <<< MAIN PROCESSING LOGIC>>> * * * Has the job been ordered to stop? * LOCK STOPPING_LOCK THEN * * no - unlock and carry on * UNLOCK STOPPING_LOCK EOF=0 END ELSE * * ordered to stop - release the running lock after tidying up * * <<< Place any closing logic here - for example: ** Closing sequntial files ** Updating control records ** etc. * UNLOCK RUNNING_LOCK; * release the lock that showed the job was running * * exit gracefully *
    A fully-worked example has been attached as three BASIC programs in source code form:

    • START_LICENSE_MONITOR - a program to launch the PHANTOM program LICENSE_MONITOR
    • LICENSE_MONITOR - a program to monitor and record U2 database license usage to a CSV file suitable for import into a spreadsheet.
    • STOP_LICENSE_MONITOR - a program to stop the PHANTOM program LICENSE_MONITOR

    The programs are fully self-documenting and  should be compiled and catalogued in an account of your choice.  To launch the monitoring program the syntax is:

    • START_LICENSE_MONITOR n
      • Where 'n' is the number of seconds between sample intervals. The default value is 5 (seconds).
    • STOP_LICENSE_MONITOR
    If wished the program can also be run directly on a terminal:

    • LICENSE_MONITOR n
      • Where 'n' is the number of seconds between sample intervals. The default value is 5 (seconds).

      Some will be well familiar with this technique, but hopefully others will find it useful as an overall control methodology. For more widespread Job Control usage it may be necessary to dynamically allocate and return pairs of available free locks from the Process Lock table, though I will leave this as an exercise for the Developer if needed.

      ------------------------------
      John Jenkins
      Principal Technical Support Engineer
      Rocket Software Limited
      U.K.
      ------------------------------

      Attachment(s)

      zip
      LICENSE_MONITOR.zip   3K 1 version