0
# Registry and Service Discovery
1
2
Service registry and discovery system for automatic service location and management. The registry enables services to advertise their availability and clients to automatically discover and connect to services by name, supporting both UDP and TCP protocols.
3
4
## Capabilities
5
6
### Registry Servers
7
8
Server implementations for hosting service registries that track available RPyC services.
9
10
```python { .api }
11
class UDPRegistryServer:
12
"""
13
UDP-based registry server for service discovery.
14
Lightweight, broadcast-enabled registry suitable for LAN environments.
15
"""
16
17
def __init__(self, host='0.0.0.0', port=18811, pruning_timeout=3, allow_listing=True):
18
"""
19
Initialize UDP registry server.
20
21
Parameters:
22
- host (str): Host address to bind to
23
- port (int): UDP port to bind to (default 18811)
24
- pruning_timeout (float): Timeout for pruning stale services
25
- allow_listing (bool): Allow service listing requests
26
"""
27
28
def start(self):
29
"""Start the registry server"""
30
31
def close(self):
32
"""Close the registry server"""
33
34
class TCPRegistryServer:
35
"""
36
TCP-based registry server for service discovery.
37
More reliable than UDP, suitable for WAN environments.
38
"""
39
40
def __init__(self, port=18811, pruning_timeout=3, allow_listing=True):
41
"""
42
Initialize TCP registry server.
43
44
Parameters:
45
- port (int): TCP port to bind to (default 18811)
46
- pruning_timeout (float): Timeout for pruning stale services
47
- allow_listing (bool): Allow service listing requests
48
"""
49
50
def start(self):
51
"""Start the registry server"""
52
53
def close(self):
54
"""Close the registry server"""
55
```
56
57
### Registry Clients
58
59
Client implementations for registering services and querying service registries.
60
61
```python { .api }
62
class UDPRegistryClient:
63
"""
64
UDP registry client for service registration and discovery.
65
"""
66
67
def __init__(self, ip='255.255.255.255', port=18811):
68
"""
69
Initialize UDP registry client.
70
71
Parameters:
72
- ip (str): Registry server IP (default broadcast)
73
- port (int): Registry server port
74
"""
75
76
def register(self, alias, port, interface=''):
77
"""
78
Register service with registry.
79
80
Parameters:
81
- alias (str): Service name/alias
82
- port (int): Service port
83
- interface (str): Network interface (optional)
84
"""
85
86
def unregister(self, port):
87
"""
88
Unregister service from registry.
89
90
Parameters:
91
- port (int): Service port to unregister
92
"""
93
94
def discover(self, name):
95
"""
96
Discover services by name.
97
98
Parameters:
99
- name (str): Service name to discover
100
101
Returns:
102
list: List of (host, port) tuples
103
"""
104
105
def list_services(self):
106
"""
107
List all available services.
108
109
Returns:
110
dict: Dictionary mapping service names to (host, port) tuples
111
"""
112
113
class TCPRegistryClient:
114
"""
115
TCP registry client for service registration and discovery.
116
"""
117
118
def __init__(self, ip='127.0.0.1', port=18811):
119
"""
120
Initialize TCP registry client.
121
122
Parameters:
123
- ip (str): Registry server IP
124
- port (int): Registry server port
125
"""
126
127
def register(self, alias, port, interface=''):
128
"""
129
Register service with registry.
130
131
Parameters:
132
- alias (str): Service name/alias
133
- port (int): Service port
134
- interface (str): Network interface (optional)
135
"""
136
137
def unregister(self, port):
138
"""
139
Unregister service from registry.
140
141
Parameters:
142
- port (int): Service port to unregister
143
"""
144
145
def discover(self, name):
146
"""
147
Discover services by name.
148
149
Parameters:
150
- name (str): Service name to discover
151
152
Returns:
153
list: List of (host, port) tuples
154
"""
155
156
def list_services(self):
157
"""
158
List all available services.
159
160
Returns:
161
dict: Dictionary mapping service names to (host, port) tuples
162
"""
163
```
164
165
### Service Registration Decorators
166
167
Decorators and utilities for automatic service registration.
168
169
```python { .api }
170
def register_service(service_class, port, registrar=None, auto_register=True):
171
"""
172
Register service class with registry for automatic discovery.
173
174
Parameters:
175
- service_class: Service class to register
176
- port (int): Port the service will run on
177
- registrar: Registry client (optional, uses default)
178
- auto_register (bool): Automatically register on server start
179
180
Returns:
181
Configured server with registry integration
182
"""
183
```
184
185
## Examples
186
187
### Setting Up UDP Registry
188
189
```python
190
from rpyc.utils.registry import UDPRegistryServer
191
import threading
192
193
# Start UDP registry server
194
registry = UDPRegistryServer(host='0.0.0.0', port=18811)
195
registry_thread = threading.Thread(target=registry.start)
196
registry_thread.start()
197
198
print("UDP Registry running on port 18811")
199
```
200
201
### Registering Services
202
203
```python
204
import rpyc
205
from rpyc.utils.server import ThreadedServer
206
from rpyc.utils.registry import UDPRegistryClient
207
208
class CalculatorService(rpyc.Service):
209
SERVICE_NAME = "CALCULATOR"
210
211
@rpyc.exposed
212
def add(self, a, b):
213
return a + b
214
215
@rpyc.exposed
216
def multiply(self, a, b):
217
return a * b
218
219
# Create registry client
220
registry = UDPRegistryClient()
221
222
# Create server with registry integration
223
server = ThreadedServer(
224
CalculatorService,
225
port=12345,
226
registrar=registry,
227
auto_register=True
228
)
229
230
print("Calculator service starting with registry integration")
231
server.start()
232
```
233
234
### Service Discovery and Connection
235
236
```python
237
import rpyc
238
from rpyc.utils.registry import UDPRegistryClient
239
240
# Create registry client
241
registry = UDPRegistryClient()
242
243
# Discover available services
244
services = registry.list_services()
245
print("Available services:", services)
246
247
# Discover specific service
248
calculator_endpoints = registry.discover("CALCULATOR")
249
if calculator_endpoints:
250
host, port = calculator_endpoints[0]
251
print(f"Found CALCULATOR service at {host}:{port}")
252
253
# Connect to discovered service
254
conn = rpyc.connect(host, port)
255
result = conn.root.add(5, 3)
256
print(f"5 + 3 = {result}")
257
conn.close()
258
else:
259
print("CALCULATOR service not found")
260
```
261
262
### TCP Registry with Multiple Services
263
264
```python
265
from rpyc.utils.registry import TCPRegistryServer, TCPRegistryClient
266
import rpyc
267
from rpyc.utils.server import ThreadedServer
268
import threading
269
270
# Start TCP registry server
271
def run_registry():
272
registry = TCPRegistryServer(port=18811)
273
registry.start()
274
275
registry_thread = threading.Thread(target=run_registry)
276
registry_thread.daemon = True
277
registry_thread.start()
278
279
# Service definitions
280
class DataService(rpyc.Service):
281
SERVICE_NAME = "DATA_PROCESSOR"
282
283
@rpyc.exposed
284
def process_data(self, data):
285
return [x * 2 for x in data]
286
287
class AuthService(rpyc.Service):
288
SERVICE_NAME = "AUTHENTICATOR"
289
290
@rpyc.exposed
291
def validate_token(self, token):
292
return token == "valid_token"
293
294
# Create registry client
295
registry_client = TCPRegistryClient()
296
297
# Start multiple services with registry
298
services = [
299
(DataService, 12001),
300
(AuthService, 12002)
301
]
302
303
servers = []
304
for service_class, port in services:
305
server = ThreadedServer(
306
service_class,
307
port=port,
308
registrar=registry_client,
309
auto_register=True
310
)
311
servers.append(server)
312
313
# Start server in background
314
server_thread = threading.Thread(target=server.start)
315
server_thread.daemon = True
316
server_thread.start()
317
318
print(f"{service_class.SERVICE_NAME} started on port {port}")
319
320
# Client discovery and usage
321
import time
322
time.sleep(1) # Wait for services to register
323
324
# List all services
325
all_services = registry_client.list_services()
326
print("All registered services:", all_services)
327
328
# Use discovered services
329
data_endpoints = registry_client.discover("DATA_PROCESSOR")
330
if data_endpoints:
331
host, port = data_endpoints[0]
332
conn = rpyc.connect(host, port)
333
result = conn.root.process_data([1, 2, 3, 4])
334
print("Processed data:", result)
335
conn.close()
336
337
auth_endpoints = registry_client.discover("AUTHENTICATOR")
338
if auth_endpoints:
339
host, port = auth_endpoints[0]
340
conn = rpyc.connect(host, port)
341
is_valid = conn.root.validate_token("valid_token")
342
print("Token validation:", is_valid)
343
conn.close()
344
```
345
346
### Registry with Service Health Monitoring
347
348
```python
349
from rpyc.utils.registry import UDPRegistryClient
350
import rpyc
351
import time
352
import threading
353
354
class MonitoredService(rpyc.Service):
355
SERVICE_NAME = "MONITORED_SERVICE"
356
357
def __init__(self):
358
self.start_time = time.time()
359
self.request_count = 0
360
361
@rpyc.exposed
362
def get_status(self):
363
uptime = time.time() - self.start_time
364
return {
365
'uptime': uptime,
366
'requests_served': self.request_count,
367
'status': 'healthy'
368
}
369
370
@rpyc.exposed
371
def process_request(self, data):
372
self.request_count += 1
373
return f"Processed: {data}"
374
375
# Service with periodic re-registration (health check)
376
def maintain_registration(service_port, registry_client):
377
while True:
378
try:
379
# Re-register every 30 seconds to show service is healthy
380
registry_client.register("MONITORED_SERVICE", service_port)
381
time.sleep(30)
382
except Exception as e:
383
print(f"Registration failed: {e}")
384
time.sleep(5)
385
386
# Start service
387
registry = UDPRegistryClient()
388
server = ThreadedServer(MonitoredService, port=12345)
389
390
# Start registration maintenance
391
registration_thread = threading.Thread(
392
target=maintain_registration,
393
args=(12345, registry)
394
)
395
registration_thread.daemon = True
396
registration_thread.start()
397
398
# Start server
399
server_thread = threading.Thread(target=server.start)
400
server_thread.daemon = True
401
server_thread.start()
402
403
print("Monitored service with health check registration started")
404
405
# Monitor service health
406
while True:
407
try:
408
services = registry.discover("MONITORED_SERVICE")
409
if services:
410
host, port = services[0]
411
conn = rpyc.connect(host, port)
412
status = conn.root.get_status()
413
print(f"Service health: {status}")
414
conn.close()
415
else:
416
print("Service not available")
417
418
time.sleep(10)
419
except KeyboardInterrupt:
420
break
421
except Exception as e:
422
print(f"Health check failed: {e}")
423
time.sleep(5)
424
```
425
426
## Constants
427
428
```python { .api }
429
REGISTRY_PORT = 18811 # Default registry port
430
DEFAULT_PRUNING_TIMEOUT = 3 # Default service timeout (seconds)
431
UDP_BROADCAST_ADDRESS = '255.255.255.255' # Default UDP broadcast address
432
```
433
434
## Exceptions
435
436
```python { .api }
437
class RegistryError(Exception):
438
"""Base exception for registry operations"""
439
440
class ServiceNotFoundError(RegistryError):
441
"""Raised when requested service is not found"""
442
443
class RegistrationError(RegistryError):
444
"""Raised when service registration fails"""
445
```