Update export statistics
This commit is contained in:
parent
863d629aa8
commit
fecefb49a1
BIN
dist/zhurnal-0.2.0-py3-none-any.whl
vendored
Normal file
BIN
dist/zhurnal-0.2.0-py3-none-any.whl
vendored
Normal file
Binary file not shown.
BIN
dist/zhurnal-0.2.0.tar.gz
vendored
Normal file
BIN
dist/zhurnal-0.2.0.tar.gz
vendored
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
Metadata-Version: 2.4
|
Metadata-Version: 2.4
|
||||||
Name: zhurnal
|
Name: zhurnal
|
||||||
Version: 0.1.0
|
Version: 0.2.0
|
||||||
Summary: Process monitoring and management web application
|
Summary: Process monitoring and management web application
|
||||||
Author: retoor
|
Author: retoor
|
||||||
Author-email: retoor@molodetz.nl
|
Author-email: retoor@molodetz.nl
|
||||||
@ -8,7 +8,7 @@ Requires-Python: >=3.8
|
|||||||
Description-Content-Type: text/markdown
|
Description-Content-Type: text/markdown
|
||||||
Requires-Dist: aiohttp
|
Requires-Dist: aiohttp
|
||||||
Requires-Dist: setuptools
|
Requires-Dist: setuptools
|
||||||
Requires-Dist: app@ git+https://retoor.molodetz.nl/retoor/app.git
|
Requires-Dist: app @ git+https://retoor.molodetz.nl/retoor/app.git
|
||||||
|
|
||||||
# Zhurnal: Real-Time Process Monitoring Web Interface 🚀
|
# Zhurnal: Real-Time Process Monitoring Web Interface 🚀
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
aiohttp
|
aiohttp
|
||||||
setuptools
|
setuptools
|
||||||
app@ git+https://retoor.molodetz.nl/retoor/app.git
|
app @ git+https://retoor.molodetz.nl/retoor/app.git
|
||||||
|
|||||||
@ -209,15 +209,15 @@ class Zhurnal(BaseApplication):
|
|||||||
self.process_tasks = {}
|
self.process_tasks = {}
|
||||||
self.shutdown_event = asyncio.Event()
|
self.shutdown_event = asyncio.Event()
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Register signal handlers for graceful shutdown
|
# Register signal handlers for graceful shutdown
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||||
loop.add_signal_handler(sig, self.handle_exit)
|
loop.add_signal_handler(sig, self.handle_exit)
|
||||||
|
|
||||||
self.on_startup.append(self.start_processes)
|
self.on_startup.append(self.start_processes)
|
||||||
self.on_cleanup.append(self.cleanup_processes)
|
self.on_cleanup.append(self.cleanup_processes)
|
||||||
|
|
||||||
self.clients = []
|
self.clients = []
|
||||||
self.router.add_get("/ws", self.websocket_handler)
|
self.router.add_get("/ws", self.websocket_handler)
|
||||||
self.router.add_get("/", self.index_handler)
|
self.router.add_get("/", self.index_handler)
|
||||||
@ -231,12 +231,12 @@ class Zhurnal(BaseApplication):
|
|||||||
async def cleanup_processes(self, app):
|
async def cleanup_processes(self, app):
|
||||||
"""Cleanup all running subprocesses."""
|
"""Cleanup all running subprocesses."""
|
||||||
log.info("Cleaning up processes...")
|
log.info("Cleaning up processes...")
|
||||||
|
|
||||||
# Terminate all running processes
|
# Terminate all running processes
|
||||||
for command, process_info in list(self.processes.items()):
|
for command, process_info in list(self.processes.items()):
|
||||||
try:
|
try:
|
||||||
# Get the subprocess
|
# Get the subprocess
|
||||||
process = process_info.get('process')
|
process = process_info.get("process")
|
||||||
if process and process.returncode is None:
|
if process and process.returncode is None:
|
||||||
log.info(f"Terminating process: {command}")
|
log.info(f"Terminating process: {command}")
|
||||||
try:
|
try:
|
||||||
@ -250,7 +250,7 @@ class Zhurnal(BaseApplication):
|
|||||||
process.kill()
|
process.kill()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error cleaning up process {command}: {e}")
|
log.error(f"Error cleaning up process {command}: {e}")
|
||||||
|
|
||||||
# Cancel any running tasks
|
# Cancel any running tasks
|
||||||
for task in list(self.process_tasks.values()):
|
for task in list(self.process_tasks.values()):
|
||||||
if not task.done():
|
if not task.done():
|
||||||
@ -297,13 +297,10 @@ class Zhurnal(BaseApplication):
|
|||||||
stdout=asyncio.subprocess.PIPE,
|
stdout=asyncio.subprocess.PIPE,
|
||||||
stderr=asyncio.subprocess.PIPE,
|
stderr=asyncio.subprocess.PIPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Store process information
|
# Store process information
|
||||||
self.processes[command] = {
|
self.processes[command] = {"process": process, "name": process_name}
|
||||||
'process': process,
|
|
||||||
'name': process_name
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(f"Running process {process_name}: {command}")
|
log.info(f"Running process {process_name}: {command}")
|
||||||
|
|
||||||
async def read_output(app, name, process, f, is_stderr=False):
|
async def read_output(app, name, process, f, is_stderr=False):
|
||||||
@ -313,15 +310,17 @@ class Zhurnal(BaseApplication):
|
|||||||
# Check if shutdown is requested
|
# Check if shutdown is requested
|
||||||
if self.shutdown_event.is_set():
|
if self.shutdown_event.is_set():
|
||||||
break
|
break
|
||||||
|
|
||||||
time_current = time.time()
|
time_current = time.time()
|
||||||
time_elapsed = round(
|
time_elapsed = round(
|
||||||
time_previous and time_current - time_previous or 0, 4
|
time_previous and time_current - time_previous or 0, 4
|
||||||
)
|
)
|
||||||
decoded_line = line.decode("utf-8", "ignore").strip()
|
decoded_line = line.decode("utf-8", "ignore").strip()
|
||||||
print(decoded_line)
|
print(decoded_line)
|
||||||
decoded_line = "".join(c for c in decoded_line if c.isprintable())
|
decoded_line = "".join(
|
||||||
|
c for c in decoded_line if c.isprintable()
|
||||||
|
)
|
||||||
|
|
||||||
# Broadcast to all WebSocket clients
|
# Broadcast to all WebSocket clients
|
||||||
for client in app.clients:
|
for client in app.clients:
|
||||||
await client.send_str(
|
await client.send_str(
|
||||||
@ -346,7 +345,13 @@ class Zhurnal(BaseApplication):
|
|||||||
# Read stdout and stderr concurrently
|
# Read stdout and stderr concurrently
|
||||||
await asyncio.gather(
|
await asyncio.gather(
|
||||||
read_output(self, f"{process_name}:stdout", process, process.stdout),
|
read_output(self, f"{process_name}:stdout", process, process.stdout),
|
||||||
read_output(self, f"{process_name}:stderr", process, process.stderr, is_stderr=True)
|
read_output(
|
||||||
|
self,
|
||||||
|
f"{process_name}:stderr",
|
||||||
|
process,
|
||||||
|
process.stderr,
|
||||||
|
is_stderr=True,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Wait for process to complete
|
# Wait for process to complete
|
||||||
@ -361,7 +366,7 @@ class Zhurnal(BaseApplication):
|
|||||||
log.error(
|
log.error(
|
||||||
f"Process {process_name}:{command} exited with non-zero status {process.returncode}."
|
f"Process {process_name}:{command} exited with non-zero status {process.returncode}."
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error(f"Error running process {process_name}: {e}")
|
log.error(f"Error running process {process_name}: {e}")
|
||||||
finally:
|
finally:
|
||||||
@ -422,5 +427,6 @@ def cli():
|
|||||||
|
|
||||||
app.run(host=args.host, port=args.port)
|
app.run(host=args.host, port=args.port)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli()
|
cli()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user