1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 12:46:49 +00:00

feat(operations): worker concurrency and job retention settings

This commit is contained in:
catborise 2026-10-13 18:12:54 +03:00
parent 18146c30a1
commit 34582d23f3
6 changed files with 94 additions and 1 deletions

View file

@ -0,0 +1,33 @@
from django.core.management.color import no_style
from django.db import migrations
SETTINGS = [
("Worker Concurrency", "WORKER_CONCURRENCY", "4", "Jobs the worker runs at the same time (1-16)"),
("Job Retention Days", "JOB_RETENTION_DAYS", "30", "Days finished jobs stay in the job history (1-3650)"),
]
def add_settings(apps, schema_editor):
setting = apps.get_model("appsettings", "AppSettings")
db_alias = schema_editor.connection.alias
# see 0014: move a PostgreSQL id sequence past the fixed ids first
with schema_editor.connection.cursor() as cursor:
for sql in schema_editor.connection.ops.sequence_reset_sql(no_style(), [setting]):
cursor.execute(sql)
for name, key, value, description in SETTINGS:
setting.objects.using(db_alias).get_or_create(
key=key, defaults={"name": name, "value": value, "choices": "", "description": description}
)
def del_settings(apps, schema_editor):
setting = apps.get_model("appsettings", "AppSettings")
db_alias = schema_editor.connection.alias
setting.objects.using(db_alias).filter(key__in=[key for _, key, _, _ in SETTINGS]).delete()
class Migration(migrations.Migration):
dependencies = [("appsettings", "0017_snapshot_free_space_settings")]
operations = [migrations.RunPython(add_settings, del_settings)]

View file

@ -1,3 +1,4 @@
from django.contrib.messages import get_messages
from django.test import RequestFactory, TestCase
from django.urls import reverse
@ -48,3 +49,8 @@ class AppSettingsTestCase(TestCase):
# a clone stays on the host of the VM it was made from; the setting
# that sent it to a random host is removed by migration 0015
self.assertFalse(AppSettings.objects.filter(key="CLONE_INSTANCE_AUTO_MIGRATE").exists())
def test_worker_settings_refuse_values_out_of_bounds(self):
response = self.client.post(reverse("appsettings"), {"WORKER_CONCURRENCY": "0"})
self.assertEqual(AppSettings.objects.get(key="WORKER_CONCURRENCY").value, "4")
self.assertTrue(any("between 1 and 16" in str(m) for m in get_messages(response.wsgi_request)))

View file

@ -51,3 +51,13 @@ class SnapshotFreeSpaceSettingsTestCase(TestCase):
limit = AppSettings._meta.get_field(field).max_length
if limit:
self.assertLessEqual(len(getattr(setting, field)), limit, f"{key} {field}")
class WorkerSettingsTestCase(TestCase):
def test_the_rows_fit_their_columns(self):
for key in ("WORKER_CONCURRENCY", "JOB_RETENTION_DAYS"):
setting = AppSettings.objects.get(key=key)
for field in ("name", "key", "value", "description"):
limit = AppSettings._meta.get_field(field).max_length
if limit:
self.assertLessEqual(len(getattr(setting, field)), limit, f"{key} {field}")

View file

@ -9,6 +9,7 @@ from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils.translation import gettext_noop as _
from logs.views import addlogmsg
from operations.utils import BOUNDS
from appsettings.models import AppSettings
@ -112,6 +113,13 @@ def appsettings(request):
for setting in appsettings:
if setting.key in request.POST:
if setting.key in BOUNDS:
low, high, _default = BOUNDS[setting.key]
raw = request.POST.get(setting.key, "")
if not (raw.isascii() and raw.isdigit() and len(raw) <= 4 and low <= int(raw) <= high):
messages.error(request, _("%(setting)s must be a whole number between %(low)s and %(high)s")
% {"setting": setting.name, "low": low, "high": high})
return HttpResponseRedirect(request.get_full_path())
try:
setting.value = request.POST.get(setting.key, "")
setting.save()