"""Трекер созданных инстансов — файловый с fcntl.flock (multi-worker gunicorn).""" import fcntl import json import os _PATH = "/tmp/instances.json" _INITIAL = { "408b7f96-6ed7-4985-be1b-f5bdcb6ab44d": {"svcId": 1, "displayName": "autotest-1", "instanceUid": "408b7f96-6ed7-4985-be1b-f5bdcb6ab44d"}, "884356cf-5212-4395-b56b-27c58a5fc1fa": {"svcId": 1, "displayName": "autotest-1-first", "instanceUid": "884356cf-5212-4395-b56b-27c58a5fc1fa"}, "6528854d-a4ea-428c-9fa4-68e85fa9b3ac": {"svcId": 1, "displayName": "curl-test-144834", "instanceUid": "6528854d-a4ea-428c-9fa4-68e85fa9b3ac"}, "fdcb5887-39f7-4ef8-a9c0-d55e434a55ff": {"svcId": 1, "displayName": "curl-final-test", "instanceUid": "fdcb5887-39f7-4ef8-a9c0-d55e434a55ff"}, } def _locked_read(): """Читает файл под эксклюзивной блокировкой, seed при отсутствии.""" try: fd = os.open(_PATH, os.O_RDWR | os.O_CREAT, 0o644) except OSError: return dict(_INITIAL) try: fcntl.flock(fd, fcntl.LOCK_EX) try: data = os.read(fd, 65536) if data: return json.loads(data.decode("utf-8")) except (json.JSONDecodeError, UnicodeDecodeError): pass # Файл пуст или битый — пишем _INITIAL data = dict(_INITIAL) os.lseek(fd, 0, 0) os.ftruncate(fd, 0) os.write(fd, json.dumps(data, indent=2).encode("utf-8")) return data finally: fcntl.flock(fd, fcntl.LOCK_UN) os.close(fd) def _locked_write(data): """Пишет файл под эксклюзивной блокировкой.""" try: fd = os.open(_PATH, os.O_RDWR | os.O_CREAT, 0o644) except OSError: return try: fcntl.flock(fd, fcntl.LOCK_EX) os.lseek(fd, 0, 0) os.ftruncate(fd, 0) os.write(fd, json.dumps(data, indent=2).encode("utf-8")) finally: fcntl.flock(fd, fcntl.LOCK_UN) os.close(fd) def add(instance_uid, svc_id, display_name): data = _locked_read() data[instance_uid] = { "svcId": svc_id, "displayName": display_name, "instanceUid": instance_uid, } _locked_write(data) def remove(instance_uid): data = _locked_read() data.pop(instance_uid, None) _locked_write(data) def list_all(): return list(_locked_read().values())