mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 02:07:36 +00:00
add proper shutdown handling
This commit is contained in:
committed by
Dion Moult
parent
10dcd9a923
commit
1672a7da32
@@ -39,7 +39,6 @@ from bpy_extras.io_utils import ExportHelper
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
# Global variables to track server processes/threads
|
|
||||||
webapp_process = None
|
webapp_process = None
|
||||||
websocket_server_thread = None
|
websocket_server_thread = None
|
||||||
websocket_app = None
|
websocket_app = None
|
||||||
@@ -54,6 +53,8 @@ class IfcTesterWebSocketServer:
|
|||||||
self.sio.attach(self.app)
|
self.sio.attach(self.app)
|
||||||
self.runner = None
|
self.runner = None
|
||||||
self.site = None
|
self.site = None
|
||||||
|
self.loop = None
|
||||||
|
self.shutdown_event = None
|
||||||
|
|
||||||
# Register namespace
|
# Register namespace
|
||||||
self.sio.register_namespace(IfcTesterNamespace("/ifctester"))
|
self.sio.register_namespace(IfcTesterNamespace("/ifctester"))
|
||||||
@@ -65,17 +66,57 @@ class IfcTesterWebSocketServer:
|
|||||||
return web.Response(text="OK", content_type="text/plain")
|
return web.Response(text="OK", content_type="text/plain")
|
||||||
|
|
||||||
async def start_server(self):
|
async def start_server(self):
|
||||||
|
self.loop = asyncio.get_event_loop()
|
||||||
|
self.shutdown_event = asyncio.Event()
|
||||||
|
|
||||||
self.runner = web.AppRunner(self.app)
|
self.runner = web.AppRunner(self.app)
|
||||||
await self.runner.setup()
|
await self.runner.setup()
|
||||||
self.site = web.TCPSite(self.runner, "127.0.0.1", self.port)
|
self.site = web.TCPSite(self.runner, "127.0.0.1", self.port)
|
||||||
await self.site.start()
|
await self.site.start()
|
||||||
print(f"IfcTester Websocket server started on 127.0.0.1:{self.port}")
|
print(f"IfcTester WebSocket server started on 127.0.0.1:{self.port}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Wait for shutdown signal
|
||||||
|
await self.shutdown_event.wait()
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
print("WebSocket server received cancellation")
|
||||||
|
finally:
|
||||||
|
await self._cleanup()
|
||||||
|
|
||||||
async def stop_server(self):
|
async def _cleanup(self):
|
||||||
if self.site:
|
try:
|
||||||
await self.site.stop()
|
# Disconnect all clients
|
||||||
if self.runner:
|
print("Shutting down SocketIO...")
|
||||||
await self.runner.cleanup()
|
|
||||||
|
try:
|
||||||
|
await self.sio.shutdown()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error shutting down socketio: {e}")
|
||||||
|
|
||||||
|
# Stop the web server
|
||||||
|
if self.site:
|
||||||
|
print("Stopping web server...")
|
||||||
|
await asyncio.wait_for(self.site.stop(), timeout=2.0)
|
||||||
|
self.site = None
|
||||||
|
|
||||||
|
# Clean up the runner
|
||||||
|
if self.runner:
|
||||||
|
print("Cleaning up runner...")
|
||||||
|
await asyncio.wait_for(self.runner.cleanup(), timeout=2.0)
|
||||||
|
self.runner = None
|
||||||
|
|
||||||
|
print("IfcTester WebSocket server stopped")
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
print("Websocket server cleanup timed out, forcing shutdown")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error during websocket cleanup: {e}")
|
||||||
|
|
||||||
|
def stop_server(self):
|
||||||
|
if self.loop and self.shutdown_event and not self.shutdown_event.is_set():
|
||||||
|
try:
|
||||||
|
self.loop.call_soon_threadsafe(self.shutdown_event.set)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error sending shutdown signal: {e}")
|
||||||
|
|
||||||
|
|
||||||
class IfcTesterNamespace(socketio.AsyncNamespace):
|
class IfcTesterNamespace(socketio.AsyncNamespace):
|
||||||
@@ -305,7 +346,6 @@ class StartIfcTesterWebapp(bpy.types.Operator):
|
|||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
try:
|
try:
|
||||||
loop.run_until_complete(websocket_app.start_server())
|
loop.run_until_complete(websocket_app.start_server())
|
||||||
loop.run_forever()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"WebSocket server error: {e}")
|
print(f"WebSocket server error: {e}")
|
||||||
finally:
|
finally:
|
||||||
@@ -390,22 +430,14 @@ class StopIfcTesterWebapp(bpy.types.Operator):
|
|||||||
# Stop websocket server
|
# Stop websocket server
|
||||||
if websocket_app and websocket_server_thread:
|
if websocket_app and websocket_server_thread:
|
||||||
try:
|
try:
|
||||||
# Create a new event loop to properly shutdown the server
|
print("Stopping WebSocket server...")
|
||||||
def shutdown_websocket():
|
|
||||||
loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(loop)
|
|
||||||
try:
|
|
||||||
loop.run_until_complete(websocket_app.stop_server())
|
|
||||||
except Exception as e:
|
|
||||||
errors.append(f"Error stopping websocket server: {str(e)}")
|
|
||||||
finally:
|
|
||||||
loop.close()
|
|
||||||
|
|
||||||
# Run shutdown in a separate thread to avoid blocking
|
# Signal shutdown using thread-safe method
|
||||||
shutdown_thread = threading.Thread(target=shutdown_websocket)
|
websocket_app.stop_server()
|
||||||
shutdown_thread.start()
|
|
||||||
shutdown_thread.join(timeout=5) # Wait up to 5 seconds
|
|
||||||
|
|
||||||
|
# Wait for the websocket thread to finish
|
||||||
|
websocket_server_thread.join(timeout=5)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
errors.append(f"Error during websocket shutdown: {str(e)}")
|
errors.append(f"Error during websocket shutdown: {str(e)}")
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
Reference in New Issue
Block a user