Reputation: 5829
I recently added a RPC backend to an existing single-threaded application as shown below
lock = Lock()
def update_state(address, value):
with lock:
state[address] = value
class ExistingClass:
def __init__(self, *args, **kwargs):
thread = Thread(target=self.start_listener)
thread.start()
def start_listener(self):
self.server = SimpleXMLRPCServer(("localhost", 8002) , allow_none=True)
self.server.register_function(update_state, "update_state")
self.server.serve_forever()
def read_state(self, address):
with lock:
return state[address]
def write_state(self, address, value):
with lock:
return state[address] = value
ec = ExistingClass()
ec.server.shutdown()
The RPC backend is run in a separate thread to allow the application to keep running.
The problem is that shutting down the application requires explicitly stopping the server and the function SimpleXMLRPCServer.shutdown()
does not work after a client has called the PRC update_state
i.e. the command ps
shows that the process is still alive post shutdown.
Initially I thought the problem could be due to the absence of a lock but that didn't resolve the problem.
Upvotes: 0
Views: 107
Reputation: 5829
I found the answer. Turns out to be simple but I'm positing this for posterity.
The RPC thread should be flagged as a daemon, i.e.
thread.daemon = True
This allows the thread to terminate when the RPC server stops.
See this post for more discussions about the daemon property.
Upvotes: 0
Reputation: 417
The issue you're facing is likely due to the fact that the server is blocked waiting for a client request to be completed. You can create a signal or flag that indicates when the server should stop. To gracefully shutdown the server, You can use a threading.Event
for this purpose.
from threading import Thread, Event
from xmlrpc.server import SimpleXMLRPCServer
from xmlrpc.server import SimpleXMLRPCRequestHandler
# ...
class ExistingClass:
def __init__(self, *args, **kwargs):
self.shutdown_event = Event()
thread = Thread(target=self.start_listener)
thread.start()
def start_listener(self):
self.server = SimpleXMLRPCServer(("localhost", 8002), allow_none=True, requestHandler=SimpleXMLRPCRequestHandler)
self.server.register_function(update_state, "update_state")
while not self.shutdown_event.is_set():
self.server.handle_request() # Handle client requests
def shutdown(self):
self.shutdown_event.set() # Set the shutdown event
self.server.server_close() # Close the server socket
# ...
ec = ExistingClass()
# To shut down the server gracefully:
ec.shutdown()
Upvotes: 0