Grotti 3.0 Phase 1: Migrationen, Pool, Queue- und Abzug-Fixes.
Nummerierte SQL-Migrationen, psycopg-Pool, waitress, hängende Queue-Jobs, sichere History-Abzüge, Chargen-Locks, Upload-/Host-Validierung, ProxyFix.
This commit is contained in:
1 parent
9e22cebb81
commit
0236278929
19 files changed
+986
-81
No files matched your search
@@ -1,19 +1,26 @@
|
||||
"""Grotti starten. Kern und Seiten liegen daneben."""
|
||||
|
||||
import atexit
|
||||
import signal
|
||||
import threading
|
||||
import time
|
||||
|
||||
from grotti import jobs, library, store
|
||||
from waitress import serve
|
||||
|
||||
from grotti import db, jobs, library, store
|
||||
from grotti.config import load
|
||||
from grotti.db import connect, prepare
|
||||
from web.app import create_app
|
||||
|
||||
|
||||
def background(cfg):
|
||||
def work():
|
||||
try:
|
||||
with connect(cfg["database_url"]) as conn:
|
||||
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:
|
||||
print("Proben gelöscht: %s" % deleted, flush=True)
|
||||
conn.commit()
|
||||
except Exception as exc:
|
||||
print("Abgleich: %s" % exc, flush=True)
|
||||
@@ -21,19 +28,79 @@ def background(cfg):
|
||||
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:
|
||||
print("Retention: %s Proben gelöscht." % n, flush=True)
|
||||
except Exception as exc:
|
||||
print("Retention: %s" % exc, flush=True)
|
||||
stop_event.wait(3600)
|
||||
|
||||
|
||||
def main():
|
||||
cfg = load()
|
||||
cfg["data_dir"].mkdir(parents=True, exist_ok=True)
|
||||
(cfg["data_dir"] / "eingang").mkdir(exist_ok=True)
|
||||
prepare(cfg["database_url"])
|
||||
with connect(cfg["database_url"]) as conn:
|
||||
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"]
|
||||
watcher.start()
|
||||
dispatcher.start()
|
||||
if hasattr(send_queue, "start"):
|
||||
send_queue.start()
|
||||
|
||||
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
|
||||
db.close_pool()
|
||||
|
||||
atexit.register(shutdown)
|
||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||
try:
|
||||
signal.signal(sig, lambda *_: shutdown())
|
||||
except (ValueError, OSError):
|
||||
pass
|
||||
|
||||
print("Grotti: http://%s:%s/" % (cfg["host"], cfg["port"]), flush=True)
|
||||
app.run(host=cfg["host"], port=cfg["port"], threaded=True, use_reloader=False)
|
||||
serve(app, host=cfg["host"], port=cfg["port"], threads=16, channel_timeout=120)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user