mirror of
https://github.com/blw1138/cross-py-builder.git
synced 2026-09-07 21:41:09 -05:00
Serialize builds and add health endpoint to build agent
- Add a non-blocking build lock so only one job runs at a time; concurrent upload/checkout requests get a 409 response - Add /healthz returning 200 when idle and 503 while a build is running - Ignore .DS_Store artifacts
This commit is contained in:
@@ -2,3 +2,4 @@ known_hosts
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
.DS_Store
|
||||
@@ -5,6 +5,7 @@ import signal
|
||||
import socket
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
|
||||
from flask import Flask, request, jsonify, send_file
|
||||
@@ -30,6 +31,7 @@ LOCAL_DIR = os.path.dirname(__file__)
|
||||
BUILD_DIR = "pybuild-data"
|
||||
TMP_DIR = tempfile.gettempdir()
|
||||
system_status = {"status": "ready", "running_job": None}
|
||||
build_lock = threading.Lock()
|
||||
|
||||
def is_windows():
|
||||
return platform.system().lower() == "windows"
|
||||
@@ -127,6 +129,12 @@ def status_page():
|
||||
return (f"{APP_NAME} - Build Agent {build_agent_version} - \n"
|
||||
f"{system_os()} | {cpu_arch()} | {version} | {hostname} | {ZeroconfServer.get_local_ip()}")
|
||||
|
||||
@app.get("/healthz")
|
||||
def healthz():
|
||||
ok = system_status['status'] == "ready"
|
||||
return jsonify({"status": "ok" if ok else "busy",
|
||||
"agent_version": build_agent_version}), 200 if ok else 503
|
||||
|
||||
@app.get("/status")
|
||||
def status():
|
||||
def get_directory_size(directory):
|
||||
@@ -173,6 +181,9 @@ def checkout_project():
|
||||
if not request.is_json or not request.json.get('repo_url'):
|
||||
return jsonify({'error': 'Repository URL is required'}), 400
|
||||
|
||||
if not build_lock.acquire(blocking=False):
|
||||
return jsonify({'error': f"Another build is already running: {system_status['running_job']}"}), 409
|
||||
|
||||
repo_url = request.json['repo_url']
|
||||
print(f"\n========== Checking Out Git Project ==========")
|
||||
|
||||
@@ -194,6 +205,8 @@ def checkout_project():
|
||||
if isinstance(e, subprocess.CalledProcessError):
|
||||
return jsonify({'error': 'Failed to clone repository'}), 500
|
||||
return jsonify({'error': f"Uncaught error processing checkout: {e}"}), 500
|
||||
finally:
|
||||
build_lock.release()
|
||||
|
||||
def safe_extract(zip_ref, dest_dir):
|
||||
"""Extract a zipfile, rejecting members that would escape dest_dir."""
|
||||
@@ -206,6 +219,9 @@ def safe_extract(zip_ref, dest_dir):
|
||||
|
||||
@app.route('/upload', methods=['POST'])
|
||||
def upload_project():
|
||||
if not build_lock.acquire(blocking=False):
|
||||
return jsonify({'error': f"Another build is already running: {system_status['running_job']}"}), 409
|
||||
|
||||
try:
|
||||
start_time = datetime.datetime.now()
|
||||
if 'file' not in request.files:
|
||||
@@ -234,6 +250,8 @@ def upload_project():
|
||||
system_status['status'] = "ready"
|
||||
shutil.rmtree(working_dir, ignore_errors=True)
|
||||
return jsonify({"error": f"Uncaught error processing job: {e}"}), 500
|
||||
finally:
|
||||
build_lock.release()
|
||||
|
||||
def install_and_build(project_path, job_id, start_time):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user