Size: 4348
Comment:
|
Size: 3224
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
= ServiceState = | = ServiceState: interface between SCM and APL = |
Line 9: | Line 9: |
{{{ServiceState}}} is a namespace that offers an interface between the Windows SCM (Service Control Manager) and a Dyalog APL application running as a service. | {{{ServiceState}}} is a namespace script that offers an interface between the Windows SCM (Service Control Manager) and a Dyalog APL application running as a service. |
Line 11: | Line 11: |
In you application workspace you need to have a function on `⎕LX` like this: | In you application workspace you need to have a function on `⎕LX` similar to this: |
Line 14: | Line 14: |
Start [1] #.WinFile.PolishCurrentDir [2] {}#.ServiceState.Init 1 3 [3] '#'⎕WS'Event'#.ServiceState.Events.QuitDQ [4] :If #.ServiceState.IsRunningAsService [5] {}#.ServiceState.EstablishServiceCallback ⍬ [6] {#.TestService.Run ⍵}&⍬ [7] ⎕DQ'.' [8] #.TestService.Off [9] :Else [10] #.TestService.Run ⍬ [11] :EndIf |
Start;ps [1] ps←#.ServiceState.CreateParmSpace [2] ps.ride←1 [3] #.ServiceState.Init ps [4] :If #.ServiceState.IsRunningAsService [5] {#.TestService.Run ⍵}&⍬ [6] ⎕DQ'.' [7] #.TestService.Off [8] :Else [9] #.TestService.Run ⍬ [10] :EndIf |
Line 28: | Line 27: |
Note that this example focuses just on getting the application running as a service. | Note that this example focuses on getting the application running as a service. For the purpose of demonstrating how to overwrite defaults (no RIDE) it shows how to create a parameter space with default settings (line [1]) and then overwrite a setting (line [2]). If you are happy with the defaults (which you can check by executing `#.ServiceState.CreateParmSpace.∆List`) then you can specify `⍬` as the right argument of `#.ServiceState.Init` in line [3]. |
Line 32: | Line 33: |
'''[1]''': This makes sure that if the workspace carries a path the work (or current) directory is set accordingly. | '''[4]''': Checks whether the application is actually running as a Windows Service. This allows to execute the application in its own thread in case its running as a service but not otherwise - that makes debugging the application significantly easier. |
Line 34: | Line 35: |
'''[2]''': This initializes the `ServiceState` interface. There are two arguments: | '''[5]''': Here we start the real application. Note that this '''must''' run in its own thread because otherwise the application might well become unresponsive. |
Line 36: | Line 37: |
1. is a boolean that indicates whether the service shall connect to Ride (1) or not (0). 2. is a positive integer specifying the number of seconds until `ServiceState` gives up waiting for the application to confirm a state change requested by the SCM (timeout). |
'''[6]''': We need to execute `⎕DQ '.'` in order to make sure that the interpreter processes all events. |
Line 39: | Line 39: |
Note that the two values are considered as constants; they are therefore established as niladic functions. For example, after having executed line [2] of the aforementioned `Start` function you can say: {{{ #.ServiceState.States.ride 1 #.ServiceState.States.timeout 3 }}} '''[3]''': `#.ServiceState.Events.QuitDQ` is a variable carrying an (any) integer. The application is supposed to send the same integer to `#` (when it wants to stop) in order to quit the `⎕DQ` on line 7. '''[4]''': Checks whether the application is actually running as a Windows Service. '''[5]''': This establishes `#.ServiceState.EstablishServiceCallback` as a callback that will handle all messages send by the Windows SCM. '''[6]''': Here we start the real application. Note that this '''must''' run in its own thread because otherwise the application might well become unresponsive. '''[7]''': We need to execute `⎕DQ '.'` in order to make sure that the interpreter processes all events. '''[8]''': At this stage we need to execute `⎕OFF`; that's what `#.TestService.Off` is doing. |
'''[7]''': At this stage we need to execute `⎕OFF`; that's what `#.TestService.Off` is doing. |
Line 62: | Line 43: |
The application must make sure that it checks whether a state change was requested. This can be done by calling certain helpers as shown in this example: | The application must make sure in its main loop that it checks for state changes, and act accordingly. This is all done by the Operator `#.ServiceState.CheckServiceMessages` which takes the name of a logging function as operand: |
Line 65: | Line 46: |
MainLoop dummmy;buffer;data;event;obj;rc;r;msg;cs [1] Log INI.CONFIG.appshortname,' server started' [2] :While 1 [3] ⎕DL 1 [4] :If #.ServiceState.ShallServicePause [5] Log'The service is pausing' [6] {}#.ServiceState.WaitForContinue ⍬ [7] Log'The service is resuming' [8] :EndIf [9] :If #.ServiceState.ShallServiceQuit [10] Log'The service is in the process of shutting down...' [11] :Leave [12] :EndIf [13] :EndWhile [14] ⎕NQ'#'#.ServiceState.Events.QuitDQ |
MainLoop dummmy;buffer;data;event;obj;rc;r;msg;cs [1] :Repeat [2] ⎕DL 1 ⍝ What is reasonable here depends on the application [3] :If (Log #.ServiceState.CheckServiceMessages)#.ServiceState.IsRunningAsService [4] Log'The service is in the process of shutting down...' [5] :Leave [6] :EndIf [7] :Until 0 |
Line 84: | Line 58: |
'''[14]''': This makes sure that the `⎕DQ` in `Start[7]` quits. Apart from `ShallServicePause` and `ShallServiceQuit` there is also a function `ShallServiceContinue` but this is called by this function: {{{ {r}←WaitForContinue dummy [1] ⍝ Returns always ⍬. [2] ⍝ Consider calling this in case ShallServicePause has returned a 1 and you don't _ [3] ⍝ have to do any particular gymnastics but just want to wait for a state change. [4] ⍝ It just waits until the status changes, although not necessarily to "continue". [5] r←⍬ [6] :While 0=ShallServiceContinue [7] ⎕DL 1 [8] :EndWhile }}} |
Line '''[3]''' checks for any changes signalled from the Service Control Manager (SCM). If a "Pause" is detected, then the function loops until either a "Continue" or a "Stop" is detected. The explicit result is 1 in case a "Stop" is detected and 0 otherwise. |
Line 112: | Line 72: |
CategoryAplTree [[CategoryAPLTreeProject]] | CategoryAplTree |
ServiceState: interface between SCM and APL
Contents
ServiceState is part of the CategoryAplTree project.
Overview
ServiceState is a namespace script that offers an interface between the Windows SCM (Service Control Manager) and a Dyalog APL application running as a service.
In you application workspace you need to have a function on ⎕LX similar to this:
Start;ps [1] ps←#.ServiceState.CreateParmSpace [2] ps.ride←1 [3] #.ServiceState.Init ps [4] :If #.ServiceState.IsRunningAsService [5] {#.TestService.Run ⍵}&⍬ [6] ⎕DQ'.' [7] #.TestService.Off [8] :Else [9] #.TestService.Run ⍬ [10] :EndIf
Note that this example focuses on getting the application running as a service. For the purpose of demonstrating how to overwrite defaults (no RIDE) it shows how to create a parameter space with default settings (line [1]) and then overwrite a setting (line [2]).
If you are happy with the defaults (which you can check by executing #.ServiceState.CreateParmSpace.∆List) then you can specify ⍬ as the right argument of #.ServiceState.Init in line [3].
Remarks:
[4]: Checks whether the application is actually running as a Windows Service. This allows to execute the application in its own thread in case its running as a service but not otherwise - that makes debugging the application significantly easier.
[5]: Here we start the real application. Note that this must run in its own thread because otherwise the application might well become unresponsive.
[6]: We need to execute ⎕DQ '.' in order to make sure that the interpreter processes all events.
[7]: At this stage we need to execute ⎕OFF; that's what #.TestService.Off is doing.
The application
The application must make sure in its main loop that it checks for state changes, and act accordingly. This is all done by the Operator #.ServiceState.CheckServiceMessages which takes the name of a logging function as operand:
MainLoop dummmy;buffer;data;event;obj;rc;r;msg;cs [1] :Repeat [2] ⎕DL 1 ⍝ What is reasonable here depends on the application [3] :If (Log #.ServiceState.CheckServiceMessages)#.ServiceState.IsRunningAsService [4] Log'The service is in the process of shutting down...' [5] :Leave [6] :EndIf [7] :Until 0
Remarks:
Line [3] checks for any changes signalled from the Service Control Manager (SCM). If a "Pause" is detected, then the function loops until either a "Continue" or a "Stop" is detected. The explicit result is 1 in case a "Stop" is detected and 0 otherwise.
Project Page
For bug reports, future enhancements and a full version history see ServiceState/ProjectPage
Version Information
Original author: |
|
Responsible: |
|
Email: |