Running SimpleXMLRPCServer in separate thread and shutting down
Asked Answered
M

3

6

I have a class that I wish to test via SimpleXMLRPCServer in python. The way I have my unit test set up is that I create a new thread, and start SimpleXMLRPCServer in that. Then I run all the test, and finally shut down.

This is my ServerThread:

class ServerThread(Thread):
    running = True
    def run(self):
        self.server = #Creates and starts SimpleXMLRPCServer

        while (self.running):
            self.server.handle_request()

    def stop(self):
        self.running = False
        self.server.server_close()

The problem is, that calling ServerThread.stop(), followed by Thread.stop() and Thread.join() will not cause the thread to stop properly if it's already waiting for a request in handle_request. And since there doesn't seem to be any interrupt or timeout mechanisms here that I can use, I am at a loss for how I can cleanly shut down the server thread.

Matt answered 2/2, 2009 at 8:59 Comment(0)
K
1

Two suggestions.

Suggestion One is to use a separate process instead of a separate thread.

  • Create a stand-alone XMLRPC server program.

  • Start it with subprocess.Popen().

  • Kill it when the test is done. In standard OS's (not Windows) the kill works nicely. In Windows, however, there's no trivial kill function, but there are recipes for this.

The other suggestion is to have a function in your XMLRPC server which causes server self-destruction. You define a function that calls sys.exit() or os.abort() or raises a similar exception that will stop the process.

Killy answered 2/2, 2009 at 11:54 Comment(2)
I'll keep this method in mind for the future. I prefer cross-platform solutions so the shutdown method seems most reasonable. I fixed it by sending a dummy request that will terminate the thread as self.running will be false.Matt
A subprocess is cross-platform. A subprocess PLUS the self-destruct method works the best.Killy
B
4

I had the same problem and after hours of research i solved it by switching from using my own handle_request() loop to serve_forever() to start the server.

serve_forever() starts an internal loop like yours. This loop can be stopped by calling shutdown(). After stopping the loop it is possible to stop the server with server_close().

I don't know why this works and the handle_request() loop don't, but it does ;P

Here is my code:

from threading import Thread
from xmlrpc.server import SimpleXMLRPCServer
from pyWebService.server.service.WebServiceRequestHandler import WebServiceRquestHandler

class WebServiceServer(Thread):
    def __init__(self, ip, port):
        super(WebServiceServer, self).__init__()
        self.running = True
        self.server = SimpleXMLRPCServer((ip, port),requestHandler=WebServiceRquestHandler)
    self.server.register_introspection_functions()

    def register_function(self, function):
        self.server.register_function(function)

    def run(self):
        self.server.serve_forever()

    def stop_server(self):
        self.server.shutdown()
        self.server.server_close()

print("starting server")
webService = WebServiceServer("localhost", 8010)
webService.start()
print("stopping server")
webService.stop_server()
webService.join()
print("server stopped")
Belize answered 2/4, 2015 at 19:38 Comment(1)
Update (python 2.7.9): I tried this, and there was no need to import WebServiceRequestHandler (or provide the handler to requestHandler).Donnie
K
1

Two suggestions.

Suggestion One is to use a separate process instead of a separate thread.

  • Create a stand-alone XMLRPC server program.

  • Start it with subprocess.Popen().

  • Kill it when the test is done. In standard OS's (not Windows) the kill works nicely. In Windows, however, there's no trivial kill function, but there are recipes for this.

The other suggestion is to have a function in your XMLRPC server which causes server self-destruction. You define a function that calls sys.exit() or os.abort() or raises a similar exception that will stop the process.

Killy answered 2/2, 2009 at 11:54 Comment(2)
I'll keep this method in mind for the future. I prefer cross-platform solutions so the shutdown method seems most reasonable. I fixed it by sending a dummy request that will terminate the thread as self.running will be false.Matt
A subprocess is cross-platform. A subprocess PLUS the self-destruct method works the best.Killy
R
0

This is my way. send SIGTERM to self. (Works for me)

Server code

import os
import signal
import xmlrpc.server

server = xmlrpc.server.SimpleXMLRPCServer(("0.0.0.0", 8000))
server.register_function(lambda: os.kill(os.getpid(), signal.SIGTERM), 'quit')
server.serve_forever()

Client code

import xmlrpc.client

c = xmlrpc.client.ServerProxy("http://localhost:8000")
try:
    c.quit()
except ConnectionRefusedError:
    pass
Roil answered 21/11, 2019 at 6:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.