<div dir="ltr"><div>I have implemented a service discovery mechanism that might work for you. This approach lets my system applications find and make available any number of services. It is influenced by zbeacon and czmq in general. While I serialise the UDP packet content using msgpack it could equally be simple strings.<br>
<br></div>Here is a brief overview:<br><br><div>// Create a discovery service on a certain UDP port<br>sdisco_t * sdisco_new (char *peer_id);<br><br>// Resolve the service endpoints for the named service.<br>void sdisco_lookup (sdisco_t *self, const char* service);<br>
<br>// Remove the named service from the list of currently unresolved services.<br>void sdisco_remove_lookup (sdisco_t *self, const char* service);<br><br>// Make the service with endpoint discoverable<br>void sdisco_add_service (sdisco_t *self, const char* service, const char *endpoint);<br>
<br>// Remove the named service and endpoint combination from being discoverable.<br>void sdisco_remove_service (sdisco_t *self, const char* service);<br><br>// Get discovery socket, for polling or receiving messages<br>void * sdisco_socket (sdisco_t *self);<br>
<br><br></div><div>The discovery mechanism binds a UDP socket to a port and listens for discovery packets, similar to zbeacon. The packets that are processed must match the version_id and a configuration_id. The configuration id allows me to run multiple system configurations ('dev' 'production', etc) on the same compute resources without interfering with each other.<br>
<br></div><div>Each discovery packets contains<br></div><div>version_id Eg. 'DISCO01'<br>peer_id Eg. 'app_1'<br></div><div>config_id Eg. user_id<br></div><div>a list of service lookups Eg. ['service_2', 'log_service']<br>
</div><div>a dict of services Eg. {'service_1': ['ipc://service_1.ipc', 'tcp://192.168.1.1:5555']}<br></div><div><br></div><div>Applications wanting to make use of the discovery mechanism must first create a discovery object using 'sdisco_new ("app_name")'. After this the app would typically put the sdisco socket into a poll loop so it's messages can be processed.<br>
<br>Service providing applications typically bind a socket and add the 
endpoint along with a service name to the discovery mechanism using the 
'sdisco_add_service' call. The discovery mechanism will emit this information after a brief interval (to minimise unnecessary emits in case the app is registering lots of services right now). After the service is broadcast once it is not broadcasted again until another application requests it. This minimises unnecessary discovery packets on the network.<br>
<br>Applications looking for a particular service make this known to the sdisco object using the 'sdisco_lookup'. The discovery mechanism emits lookup packets at a configurable interval for as long as it has unresolved lookups. <br>
<br>When emitting lookup requests the discovery packet does not populate the services dict. When the discovery mechanism resolves a lookup it returns this on its socket and removes the lookup from its list of unresolved lookups.<br>
<br></div><div>So far the method seems to work well for my system of C and Python applications. It lets me create applications with numerous discoverable services (eg. control, diagnostics, logging, etc) and it only emits discovery messages when necessary.<br>
</div><div><br></div><div>Hopefully this was of interest and informative. Perhaps you could make your own based on a similar method?<br></div><div><br></div><div><br></div></div>