feat: switch WEB to shared hot pool with autoscale
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
<section class="panel">
|
||||
<div class="admin-intro">
|
||||
Основной режим: <b>WEB</b>. Пользователь выбирает сервис, а портал открывает нужный URL в заранее прогретом браузере.
|
||||
Поле <b>pool size</b> задаёт, сколько таких прогретых контейнеров держать для конкретного сервиса.
|
||||
Для WEB используется <b>общий пул</b> горячих контейнеров с автодоращиванием по занятости.
|
||||
</div>
|
||||
</section>
|
||||
<section class="panel">
|
||||
@@ -90,7 +90,15 @@
|
||||
<section id="tab-web" class="panel admin-tab" style="display:none;">
|
||||
<h3>WEB сервисы</h3>
|
||||
<div class="admin-intro">
|
||||
<b>Как читать статусы:</b> в строке сервиса <b>прогрето X / Y</b> и <b>занято: N</b> относятся к этому конкретному сервису.
|
||||
<b>Как читать статусы:</b> прогрето X / Y — это состояние общего WEB-пула, занято: N — активные сессии конкретного сервиса.
|
||||
</div>
|
||||
<div class="panel" style="padding:0.8rem;">
|
||||
<div class="list-title">Настройки общего WEB pool</div>
|
||||
<div class="actions">
|
||||
<input id="web_pool_size" type="number" min="0" value="{{ web_pool_size }}" style="max-width:220px;" />
|
||||
<button onclick="saveWebPoolSize()">Save WEB pool size</button>
|
||||
</div>
|
||||
<small>Автодоращивание: active + {{ web_pool_buffer }}</small>
|
||||
</div>
|
||||
<div class="summary-strip">
|
||||
<div class="summary-card">
|
||||
@@ -112,7 +120,7 @@
|
||||
<input class="list-search" id="web_search" placeholder="Поиск WEB сервиса..." oninput="filterList('web_search', '#web_list .web-item')" />
|
||||
<div class="list-box" id="web_list">
|
||||
{% for s in web_services %}
|
||||
<button class="list-item service-row web-item" data-service-id="{{s.id}}" data-filter="{{(s.name ~ ' ' ~ s.slug)|lower}}" onclick='selectWebService({{s.id}}, {{s.name|tojson}}, {{s.slug|tojson}}, {{s.target|tojson}}, {{s.comment|tojson}}, {{s.icon_path|tojson}}, {{s.active|tojson}}, {{s.warm_pool_size}})'>
|
||||
<button class="list-item service-row web-item" data-service-id="{{s.id}}" data-filter="{{(s.name ~ ' ' ~ s.slug)|lower}}" onclick='selectWebService({{s.id}}, {{s.name|tojson}}, {{s.slug|tojson}}, {{s.target|tojson}}, {{s.comment|tojson}}, {{s.icon_path|tojson}}, {{s.active|tojson}})'>
|
||||
<img class="service-thumb" src="{{ s.icon_path or '/static/service-placeholder.svg' }}" alt="icon" />
|
||||
<div>
|
||||
<div>{{s.name}}</div>
|
||||
@@ -147,11 +155,6 @@
|
||||
<textarea id="w_comment" placeholder="Коротко: что это за сервис"></textarea>
|
||||
</label>
|
||||
|
||||
<label class="field-col">
|
||||
<span>Сколько держать прогретых</span>
|
||||
<input id="w_pool" type="number" min="0" placeholder="Например: 2" />
|
||||
</label>
|
||||
|
||||
<label class="field-col">
|
||||
<span>Статус</span>
|
||||
<select id="w_active"><option value="true">active</option><option value="false">inactive</option></select>
|
||||
@@ -159,7 +162,6 @@
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button onclick="saveWebService()">Save</button>
|
||||
<button onclick="prewarmNow('w_id')">Prewarm now</button>
|
||||
<button onclick="deleteService('w_id')">Delete</button>
|
||||
<button onclick="clearWebForm()">Clear</button>
|
||||
</div>
|
||||
@@ -204,7 +206,7 @@
|
||||
|
||||
<hr>
|
||||
<div class="list-title">Добавить WEB</div>
|
||||
<div class="field-help">Рекомендуется начинать с pool size = 2-3 для часто используемых сервисов.</div>
|
||||
<div class="field-help">Горячий пул задается сверху и общий для всех WEB сервисов.</div>
|
||||
<div class="form-grid labelled-grid">
|
||||
<input id="new_w_slug" type="hidden" />
|
||||
|
||||
@@ -223,11 +225,6 @@
|
||||
<textarea id="new_w_comment" placeholder="Коротко: что это за сервис"></textarea>
|
||||
</label>
|
||||
|
||||
<label class="field-col">
|
||||
<span>Сколько держать прогретых</span>
|
||||
<input id="new_w_pool" type="number" min="0" value="2" placeholder="Например: 2" />
|
||||
</label>
|
||||
|
||||
<label class="field-col">
|
||||
<span>Статус</span>
|
||||
<select id="new_w_active"><option value="true">active</option><option value="false">inactive</option></select>
|
||||
@@ -593,20 +590,25 @@
|
||||
location.reload();
|
||||
}
|
||||
|
||||
function selectWebService(id, name, slug, target, comment, iconPath, active, pool) {
|
||||
function selectWebService(id, name, slug, target, comment, iconPath, active) {
|
||||
document.getElementById('w_id').value = id;
|
||||
document.getElementById('w_name').value = name;
|
||||
document.getElementById('w_slug').value = slug;
|
||||
document.getElementById('w_target').value = target;
|
||||
document.getElementById('w_comment').value = comment || '';
|
||||
document.getElementById('w_active').value = String(active);
|
||||
document.getElementById('w_pool').value = pool;
|
||||
document.getElementById('w_icon_preview').src = iconPath || placeholderIcon;
|
||||
document.getElementById('w_health_box').style.display = 'block';
|
||||
markSelected('.web-item', 'data-service-id', id);
|
||||
refreshSelectedServiceStatus('web');
|
||||
}
|
||||
|
||||
async function saveWebPoolSize() {
|
||||
const size = parseInt(document.getElementById('web_pool_size').value || '0', 10);
|
||||
await api('/api/admin/web-pool-size', 'PUT', {size});
|
||||
location.reload();
|
||||
}
|
||||
|
||||
async function createWebService() {
|
||||
const slug = document.getElementById('new_w_slug').value || slugifyRu(document.getElementById('new_w_name').value);
|
||||
await api('/api/admin/services', 'POST', {
|
||||
@@ -615,7 +617,6 @@
|
||||
type: 'WEB',
|
||||
target: document.getElementById('new_w_target').value,
|
||||
comment: document.getElementById('new_w_comment').value,
|
||||
warm_pool_size: parseInt(document.getElementById('new_w_pool').value || '0', 10),
|
||||
active: document.getElementById('new_w_active').value === 'true',
|
||||
});
|
||||
location.reload();
|
||||
@@ -631,14 +632,13 @@
|
||||
type: 'WEB',
|
||||
target: document.getElementById('w_target').value,
|
||||
comment: document.getElementById('w_comment').value,
|
||||
warm_pool_size: parseInt(document.getElementById('w_pool').value || '0', 10),
|
||||
active: document.getElementById('w_active').value === 'true',
|
||||
});
|
||||
location.reload();
|
||||
}
|
||||
|
||||
function clearWebForm() {
|
||||
['w_id','w_name','w_slug','w_target','w_comment','w_pool'].forEach(id => document.getElementById(id).value = '');
|
||||
['w_id','w_name','w_slug','w_target','w_comment'].forEach(id => document.getElementById(id).value = '');
|
||||
document.getElementById('w_active').value = 'true';
|
||||
document.getElementById('w_icon_preview').src = placeholderIcon;
|
||||
document.getElementById('w_health_box').style.display = 'none';
|
||||
|
||||
Reference in New Issue
Block a user