first commit
Verify / test (push) Failing after 2m54s

This commit is contained in:
2026-11-05 17:31:17 +03:30
کامیت 56c5ee23d3
63فایلهای تغییر یافته به همراه2749 افزوده شده و 0 حذف شده
+68
مشاهده پرونده
@@ -0,0 +1,68 @@
"""Run `python -m app.worker`; add replicas to scale parsing independently of API."""
import json
import logging
import os
from pathlib import Path
import signal
import subprocess
import sys
import tempfile
import time
from sqlalchemy import update
from .config import settings
from .cleanup import cleanup
from .db import Job, claim, initialize, sessions
from .storage import storage
log = logging.getLogger(__name__)
stopping = False
def process(job):
config = settings()
prefix = f"{job['id']}/attempt-{job['attempt']}"
try:
with tempfile.TemporaryDirectory(prefix='schdoc-') as directory:
root = Path(directory)
source = root / 'input.SchDoc'
source.write_bytes(storage().get(job['input_key']))
env = {k: v for k, v in os.environ.items() if k in ('PATH', 'LANG', 'LC_ALL', 'PYTHONPATH')}
# Drain no untrusted output into logs. Kill/wait is handled by subprocess.run.
subprocess.run([sys.executable, '-m', 'app.parse_task', str(source), str(root), job['filename'], job['id']],
timeout=config.parse_timeout, check=True, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
result = json.loads((root / 'result.json').read_text())
if result['ok']:
storage().put(prefix + '/data.json', (root / 'data.json').read_bytes(), 'application/json')
storage().put(prefix + '/drawing.svg', (root / 'drawing.svg').read_bytes(), 'image/svg+xml')
values = dict(status='completed', output_prefix=prefix, summary=json.dumps(result['summary']))
else:
values = dict(status='failed', error_code=result['code'], error_message=result['message'])
except subprocess.TimeoutExpired:
values = dict(status='failed', error_code='parse_timeout', error_message='Schematic exceeded the parsing time limit')
except subprocess.CalledProcessError:
values = dict(status='failed', error_code='parse_resource_limit', error_message='Parser exited before completion (resource limit or invalid input)')
except Exception:
log.exception('Worker infrastructure failure for %s', job['id'])
values = dict(status='failed', error_code='processing_error', error_message='Storage or processing service unavailable')
with sessions().begin() as db:
# An expired worker may finish late. Its outputs must never replace a newer attempt.
db.execute(update(Job).where(Job.id == job['id'], Job.attempt == job['attempt'], Job.status == 'processing')
.values(**values, lease_until=None, updated_at=time.time()))
def main():
global stopping
logging.basicConfig(level=logging.INFO)
def stop(*_):
global stopping
stopping = True
signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGINT, stop)
initialize()
last_cleanup=0
while not stopping:
if time.monotonic()-last_cleanup>60:
cleanup(); last_cleanup=time.monotonic()
job = claim()
if job: process(job)
else: time.sleep(0.5)
if __name__ == '__main__': main()