v1.0.53: file-based tracker with fcntl.flock (multi-worker gunicorn fix)
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ from routes.main import bp as main_bp
|
|||||||
from routes.api import bp as api_bp
|
from routes.api import bp as api_bp
|
||||||
from routes.api_test import bp as api_test_bp
|
from routes.api_test import bp as api_test_bp
|
||||||
|
|
||||||
VERSION = "1.0.52"
|
VERSION = "1.0.53"
|
||||||
|
|
||||||
app = Flask(__name__, template_folder="templates", static_folder="static")
|
app = Flask(__name__, template_folder="templates", static_folder="static")
|
||||||
app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc")
|
app.config["NUBES_API_ENDPOINT"] = os.getenv("NUBES_API_ENDPOINT", "https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc")
|
||||||
|
|||||||
+54
-10
@@ -1,9 +1,11 @@
|
|||||||
"""Трекер созданных инстансов — in-memory dict (один gunicorn worker)."""
|
"""Трекер созданных инстансов — файловый с fcntl.flock (multi-worker gunicorn)."""
|
||||||
import threading
|
import fcntl
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
_LOCK = threading.Lock()
|
_PATH = "/tmp/instances.json"
|
||||||
|
|
||||||
_data = {
|
_INITIAL = {
|
||||||
"408b7f96-6ed7-4985-be1b-f5bdcb6ab44d": {"svcId": 1, "displayName": "autotest-1", "instanceUid": "408b7f96-6ed7-4985-be1b-f5bdcb6ab44d"},
|
"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"},
|
"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"},
|
"6528854d-a4ea-428c-9fa4-68e85fa9b3ac": {"svcId": 1, "displayName": "curl-test-144834", "instanceUid": "6528854d-a4ea-428c-9fa4-68e85fa9b3ac"},
|
||||||
@@ -11,20 +13,62 @@ _data = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
def add(instance_uid, svc_id, display_name):
|
||||||
with _LOCK:
|
data = _locked_read()
|
||||||
_data[instance_uid] = {
|
data[instance_uid] = {
|
||||||
"svcId": svc_id,
|
"svcId": svc_id,
|
||||||
"displayName": display_name,
|
"displayName": display_name,
|
||||||
"instanceUid": instance_uid,
|
"instanceUid": instance_uid,
|
||||||
}
|
}
|
||||||
|
_locked_write(data)
|
||||||
|
|
||||||
|
|
||||||
def remove(instance_uid):
|
def remove(instance_uid):
|
||||||
with _LOCK:
|
data = _locked_read()
|
||||||
_data.pop(instance_uid, None)
|
data.pop(instance_uid, None)
|
||||||
|
_locked_write(data)
|
||||||
|
|
||||||
|
|
||||||
def list_all():
|
def list_all():
|
||||||
with _LOCK:
|
return list(_locked_read().values())
|
||||||
return list(_data.values())
|
|
||||||
|
|||||||
Reference in New Issue
Block a user