Service discovery
.px.sd. addCallbacks add callbacks for logon and logoff events checkRunning whether a service is running executeLogon execute new logon callback for all running services getClass get services based on a class getHostPort get host and port for a service getHostPorts get hosts and ports for services getService get a cached service getServices get cached services getTemplate get services based on a table init initiate the module state logoff set the logoff callback for a service logon set the logon callback for a service
This module provides the ability to do service discovery. Solutions can use it to subscribe to updates of processes starting and stopping. The Control process acts as the discovery service by publishing messages when services logon or logoff.
This module is instantiated by a call to .px.sd.init
. This subscribes to Control
for service updates and caches the current state locally in the process.
For simple clients who only need to periodically check the service state, they can use the APIs described in this module to check the current state.
Supported operations are
- get cached services table
- get details for single or multiple services
- get host and port for single or multiple services
- get services by class or template
Other clients may need to actively know when the service list changes. In this mode clients should implement handlers for logon and logoff events. For processes that take actions on logoff, please note the warning below.
Service logoff
Broadcast messages only indicate the status of the service to Control connection. A service may disconnect from Control but still be running. In this case it is up to the client to decide how to handle this scenario.
The suggested approach is to treat the process as disconnected only if a logoff broacast is received and the connection from the client to this service is disconnected. Therefore, the client should implement logoff and disconnect handlers that check both the Control and the handle status.
Active client
An example service client is implemented to illustrate how this works. The example is going to create a module to connect to running services. This module creates a table to maintain the online state of each service and connection to each of them. The state of each service is updated through logon/off event handlers.
- Define a table which will store running services
- Define a timer function to connect to each service and cache the handle
- Define the disconnect function
- this disconnects services if still they are still running
- if not running, it removes them from the table
// Store running services
.sol.runningServices:1!flip `process`class`handle!"ssi"$\:()
// Define the logon callback analytic
.sol.connect:{[]
data:select process, handle:@[hopen; ; 0Ni]
each .px.sd.getHostPorts[process] from .px.sd.running;
`.sol.runningServices upsert data; }
// Add connect function to timer
.d.prcl.addFunctToTimer[`.sol.connect; (); 0Nz; 0Wz; 1000i; 1b]
// Define the logoff callback analytic which takes the handle
.sol.serviceDisconnect:{[hn]
cl:0!select from .sol.runningServices where handle=hn;
if[not count cl; :()];
.log.out[.z.h;"Service disconnect for process "; pname:first cl`process];
$[.px.sd.checkRunning[pname];
update handle:0Ni from `.sol.runningServices where process=pname;
delete from `.sol.runningServices where process=pname
]; }
The below code defines the logon and logoff callbacks. These will be triggered whenever the list of running services changes.
.sol.serv.logon:{[x]
.log.out[.z.h;"New service available";`process`port!(x`process;x`port)];
`.sol.runningServices upsert select process, class from x; }
.sol.serv.logoff:{[x]
if[not null .sol.runningServices[x`process]`handle; :()];
.log.out[.z.h;"Service logged off";`process`port!(x`process;x`port)];
delete from `.sol.runningServices where process=x`process; }
After the above functions are defined, the module can be initialized by
defining the callbacks and running the init
method.
.px.sd.addCallbacks[`.sol.serv.logon; `.sol.serv.logoff]
.px.sd.init[]
Passive client
For a passive client, services details can be requested using a set of public APIs.
.px.sd.checkRunning Check if a service is running
.px.sd.getClass Get services based on their class
.px.sd.getHostPort/s Get the hostport of a services
.px.sd.getServices Get the cached services
.px.sd.getTemplate Get all running services based on their template
.px.sd.addCallbacks
Add callbacks for logon and logoff events
.px.sd.addCallbacks[x;y]
Where x
and y
are symbol atoms naming a logon API, sets corresponding callbacks – null for a null symbol.
.px.sd.addCallbacks[`.qr.serv.logon; `.qr.serv.logoff]
No logoff handler:
.px.sd.addCallbacks[`.qr.serv.logon; `]
.px.sd.checkRunning
Check if a service is running
.px.sd.checkRunning x
Where x
is the name of a process as a symbol atom, returns as a boolean whether the process is running.
q).px.sd.checkRunning `fx_rdb_143
1b
.px.sd.executeLogon
Execute new logon callback for all running services
.px.sd.executeLogon x
Where x
is the name of a logon API as a symbol atom, executes the callback for all running services.
.px.sd.getClass
Get services based on class
.px.sd.getClass x
Where x
is a class or list of classes as a symbol atom or vector, returns a table of running services of those classes.
q).px.sd.getClass[`fx_qp`fx_hdb]
process host port tls template class
--------------------------------------------------------------------
fx_qp_142 dev-ubuntu.firstderivatives.com 45737 off DS_QP fx_qp
.px.sd.getHostPort
Get host and port for a service
.px.sd.getHostPort x
Where x
is the name of a process as a symbol atom, returns as a symbol the corresponding host and port.
q).px.sd.getHostPort `fx_rdb_143
`:dev-ubuntu.firstderivatives.com:33715
.px.sd.getHostPorts
Get hosts and ports for a list of services
.px.sd.getHostPorts x
Where x
is the names of processes as a symbol vector, returns as a symbol list the corresponding hosts and ports.
q).px.sd.getHostPorts `fx_rdb_143`fx_qp_142
`:dev-ubuntu.firstderivatives.com:33715`:dev-ubuntu.firstderivatives.com:45737
.px.sd.getService
Get a cached service
.px.sd.getService x
Where x
is a process name as a symbol atom, returns a dictionary of information about it.
q).px.sd.getService[`fx_rdb_143]
process | fx_rdb_143
class | fx_rdb
host | dev-ubuntu.firstderivatives.com
port | 33715
tls | off
template| DS_RDB
.px.sd.getServices
Get the cached services
.px.sd.getServices x
Where x
is a list of process names as a symbol vector, returns a table of information about them.
The generic null denotes all processes.
q).px.sd.getServices (::)
process class host port tls template
--------------------------------------------------------------------
fx_rdb_140 fx_rdb dev-ubuntu.firstderivatives.com 38040 off DS_RDB
fx_rdb_141 fx_rdb dev-ubuntu.firstderivatives.com 46576 off DS_RDB
fx_qp_142 fx_qp dev-ubuntu.firstderivatives.com 45737 off DS_QP
fx_rdb_143 fx_rdb dev-ubuntu.firstderivatives.com 33715 off DS_RDB
q)q_.px.sd.getServices `fx_rdb_143`fx_qp_142
process class host port tls template
--------------------------------------------------------------------
fx_qp_142 fx_qp dev-ubuntu.firstderivatives.com 45737 off DS_QP
fx_rdb_143 fx_rdb dev-ubuntu.firstderivatives.com 33715 off DS_RDB
.px.sd.getTemplate
Get services based on templates
.px.sd.getTemplate x
Where x
is the template name of a process as a symbol atom, returns a table of corresponding processes.
q).px.sd.getTemplate[`DS_RDB]
process class host port tls template
--------------------------------------------------------------------
fx_rdb_140 fx_rdb dev-ubuntu.firstderivatives.com 38040 off DS_RDB
fx_rdb_141 fx_rdb dev-ubuntu.firstderivatives.com 46576 off DS_RDB
fx_rdb_143 fx_rdb dev-ubuntu.firstderivatives.com 33715 off DS_RDB
.px.sd.init
Initiate the module state
.px.sd.init[]
Initiates the module state and returns null.
.px.sd.logoff
Set the callback for when a service logs off
.px.sd.logoff[x;y]
Where
x
is a broadcast topic as a symbol atomy
is a dictionary of service details
sets the callback for when the service logs off.
q)data
process | `fx_rdb_a
class | `fx_rdb
host | `localhost
port | 3000
tls | `
template| `DS_RDB
q).px.sd.logoff[`Service.Logoff; data]
.px.sd.logon
Set the callback for when a new service comes online
.px.sd.logon[x;y]
x
is a broadcast topic as a symbol atomy
is a dictionary of service details
sets the callback for when the service logs on.
q)data
process | `fx_rdb_a
class | `fx_rdb
host | `localhost
port | 3000
tls | `
template| `DS_RDB
q).px.sd.logon[`Service.Logon; data]