Files
grotti/server.py
T
Dominic Gundel db6a85a703 Grotti 3.7.0: Treiber für Kobra 4 und Marlin, smartere Dateien-Auswahl und einstellbare Etiketten.
Senden und Abbruch laufen über den Treiber, Orca-Doppelzeilen und tote Ideen-API fallen weg, Drucker folgen der Datei, Etikettenformat liegt in den Einstellungen.
2026-11-02 14:03:57 +01:00

128 lines
3.6 KiB
Python

"""Grotti starten. Kern und Seiten liegen daneben."""
import atexit
import signal
import threading
import time
from waitress import serve
from grotti import db, jobs, library, logutil, store
from grotti.marlin_supervisor import enable as enable_marlin
from grotti.config import load
from web.app import create_app
log = logutil.get("grotti.server")
def background(cfg):
def work():
try:
with db.connect(cfg["database_url"]) as conn:
library.sync_watch(conn, cfg, force=False)
jobs.sync_history(conn, cfg)
deleted = db.prune_run_samples(conn, keep_days=90)
if deleted:
log.info("Proben gelöscht: %s", deleted)
conn.commit()
except Exception as exc:
log.warning("Abgleich: %s", exc)
threading.Thread(target=work, name="grotti-abgleich", daemon=True).start()
def _retention_loop(cfg, stop_event):
"""Nächtlich alte run_samples entfernen."""
while not stop_event.wait(3600):
hour = time.localtime().tm_hour
if hour != 3:
continue
try:
with db.connect(cfg["database_url"]) as conn:
n = db.prune_run_samples(conn, keep_days=90)
conn.commit()
if n:
log.info("Retention: %s Proben gelöscht.", n)
except Exception as exc:
log.warning("Retention: %s", exc)
stop_event.wait(3600)
def main():
cfg = load()
logutil.setup(cfg.get("log_level") or "INFO")
cfg["data_dir"].mkdir(parents=True, exist_ok=True)
(cfg["data_dir"] / "eingang").mkdir(exist_ok=True)
db.prepare(cfg["database_url"])
db.init_pool(cfg["database_url"], min_size=2, max_size=16)
with db.connect(cfg["database_url"]) as conn:
store.seed_printers(conn, cfg["printers_file"])
store.seed_materials(conn)
conn.commit()
app = create_app(cfg)
watcher = app.extensions["watcher"]
dispatcher = app.extensions["print_queue"]
send_queue = app.extensions["send_queue"]
enable_marlin(cfg["data_dir"])
watcher.start()
dispatcher.start()
if hasattr(send_queue, "start"):
send_queue.start()
from grotti.daily_report import DailyReportThread
daily = DailyReportThread(cfg["database_url"], cfg, watcher=watcher)
daily.start()
app.extensions["daily_report"] = daily
stop_event = threading.Event()
retention = threading.Thread(
target=_retention_loop,
args=(cfg, stop_event),
name="grotti-retention",
daemon=True,
)
retention.start()
background(cfg)
def shutdown(*_args):
stop_event.set()
try:
watcher.stop()
except Exception:
pass
try:
dispatcher.stop()
except Exception:
pass
try:
if hasattr(send_queue, "stop"):
send_queue.stop()
except Exception:
pass
try:
daily.stop()
except Exception:
pass
db.close_pool()
# Der Marlin-Dienst bleibt. Ein Stopp hier würde den Druck abbrechen.
atexit.register(shutdown)
for sig in (signal.SIGINT, signal.SIGTERM):
try:
signal.signal(sig, lambda *_: shutdown())
except (ValueError, OSError):
pass
log.info("Grotti: http://%s:%s/", cfg["host"], cfg["port"])
serve(
app,
host=cfg["host"],
port=cfg["port"],
threads=int(cfg.get("http_threads") or 16),
channel_timeout=120,
)
if __name__ == "__main__":
main()