Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2068af106f | |||
| 06c2270842 | |||
| 20556f3500 | |||
| 7f1d616bb3 |
@@ -155,10 +155,12 @@ select:focus {
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.container {
|
||||
width: calc(100% - 18px);
|
||||
padding: 14px;
|
||||
margin: 10px auto;
|
||||
border-radius: 10px;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 12px 12px 18px;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+194
-5
@@ -136,6 +136,10 @@
|
||||
top: 0;
|
||||
z-index: 1900;
|
||||
}
|
||||
|
||||
.navbar .container-fluid {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-weight: bold;
|
||||
@@ -538,22 +542,200 @@
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.module-selector-bar {
|
||||
padding: 8px 12px;
|
||||
.navbar {
|
||||
border-bottom-left-radius: 14px;
|
||||
border-bottom-right-radius: 14px;
|
||||
}
|
||||
|
||||
.navbar .container-fluid {
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 0.2rem;
|
||||
padding-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
order: 1;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
font-size: 1.08rem;
|
||||
line-height: 1.1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding-top: 0.2rem;
|
||||
padding-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
order: 2;
|
||||
margin-left: auto;
|
||||
flex: 0 0 auto;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.navbar-collapse {
|
||||
order: 4;
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
padding: 10px 10px 6px;
|
||||
border-radius: 14px;
|
||||
background: rgba(15, 23, 42, 0.18);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.navbar-collapse.show,
|
||||
.navbar-collapse.collapsing {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
width: 100%;
|
||||
align-items: stretch;
|
||||
gap: 8px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
min-height: 46px;
|
||||
padding: 0.8rem 0.95rem;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link.nav-active,
|
||||
.navbar-nav .nav-link.quick-link-pill,
|
||||
.navbar-nav .nav-link.nav-priority-link {
|
||||
background: rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
.navbar-nav .nav-item.dropdown {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-item.dropdown .nav-link.dropdown-toggle {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.navbar-nav .dropdown-menu {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
margin-top: 6px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.module-selector-bar {
|
||||
padding: 8px 10px;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.module-selector-bar .module-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.module-selector-bar .module-tabs {
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.module-selector-bar .module-tab {
|
||||
padding: 5px 12px;
|
||||
font-size: 0.9rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 8px 12px;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.module-separator {
|
||||
height: 18px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.function-search-wrap {
|
||||
order: 3;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.function-search-form {
|
||||
width: 100%;
|
||||
flex-wrap: nowrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.function-search-input {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.function-search-btn {
|
||||
flex: 0 0 auto;
|
||||
min-height: 44px;
|
||||
min-width: 72px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.navbar-text {
|
||||
order: 5;
|
||||
width: 100%;
|
||||
margin: 0 !important;
|
||||
padding: 8px 10px;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.user-menu-wrap {
|
||||
order: 6;
|
||||
width: 100%;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.user-menu-btn {
|
||||
width: 100%;
|
||||
min-height: 46px;
|
||||
border-radius: 12px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dropdown-menu-end {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navbar-mobile-arranged .navbar-collapse {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.navbar-mobile-arranged .navbar-nav {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body.nav-mobile-tight .function-search-form {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body.nav-mobile-tight .function-search-input,
|
||||
body.nav-mobile-tight .function-search-btn,
|
||||
body.nav-mobile-tight .user-menu-btn,
|
||||
body.nav-mobile-tight .module-selector-bar .module-tab {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.nav-mobile-tight .module-selector-bar .module-tabs {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body.nav-mobile-tight .navbar-text {
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1286,6 +1468,13 @@
|
||||
if (!navRoot || !navContainer) return;
|
||||
const width = navContainer.clientWidth || window.innerWidth;
|
||||
navRoot.classList.remove('nav-compact', 'nav-ultra-compact');
|
||||
navRoot.classList.toggle('nav-mobile-arranged', window.innerWidth < 992);
|
||||
navRoot.classList.toggle('nav-mobile-tight', window.innerWidth < 520);
|
||||
|
||||
if (document.body) {
|
||||
document.body.classList.toggle('nav-mobile-arranged', window.innerWidth < 992);
|
||||
document.body.classList.toggle('nav-mobile-tight', window.innerWidth < 520);
|
||||
}
|
||||
|
||||
if (window.innerWidth < 992) {
|
||||
return;
|
||||
|
||||
+46
-11
@@ -774,8 +774,18 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const distanceToEnd = itemsContainer.scrollWidth - (itemsContainer.scrollLeft + itemsContainer.clientWidth);
|
||||
const prefetchThreshold = Math.max(260, itemsContainer.clientWidth * 1.4);
|
||||
const styles = window.getComputedStyle(itemsContainer);
|
||||
const isMobileLayout =
|
||||
window.matchMedia('(max-width: 768px)').matches ||
|
||||
styles.display === 'grid' ||
|
||||
styles.flexDirection === 'column';
|
||||
|
||||
const distanceToEnd = isMobileLayout
|
||||
? itemsContainer.scrollHeight - (itemsContainer.scrollTop + itemsContainer.clientHeight)
|
||||
: itemsContainer.scrollWidth - (itemsContainer.scrollLeft + itemsContainer.clientWidth);
|
||||
const prefetchThreshold = isMobileLayout
|
||||
? Math.max(220, itemsContainer.clientHeight * 0.9)
|
||||
: Math.max(260, itemsContainer.clientWidth * 1.4);
|
||||
if (distanceToEnd > prefetchThreshold) {
|
||||
return;
|
||||
}
|
||||
@@ -1142,6 +1152,12 @@
|
||||
const itemsContainer = ensureMainItemsSentinel();
|
||||
if (!itemsContainer) return;
|
||||
|
||||
const styles = window.getComputedStyle(itemsContainer);
|
||||
const isMobileLayout =
|
||||
window.matchMedia('(max-width: 768px)').matches ||
|
||||
styles.display === 'grid' ||
|
||||
styles.flexDirection === 'column';
|
||||
|
||||
if (mainItemsObserver) {
|
||||
mainItemsObserver.disconnect();
|
||||
mainItemsObserver = null;
|
||||
@@ -1172,7 +1188,7 @@
|
||||
}, {
|
||||
root: itemsContainer,
|
||||
threshold: 0.15,
|
||||
rootMargin: '0px 900px 0px 0px'
|
||||
rootMargin: isMobileLayout ? '0px 0px 900px 0px' : '0px 900px 0px 0px'
|
||||
});
|
||||
|
||||
mainItemsObserver.observe(mainItemsSentinel);
|
||||
@@ -2942,6 +2958,22 @@
|
||||
animation: items-loader-slide 1.05s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.items-loading-indicator {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
min-height: 120px;
|
||||
height: auto;
|
||||
padding: 14px 10px;
|
||||
scroll-snap-align: none;
|
||||
}
|
||||
|
||||
.items-loading-indicator .loading-track {
|
||||
width: min(240px, 82%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes items-loader-slide {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(260%); }
|
||||
@@ -3342,9 +3374,12 @@
|
||||
|
||||
/* Mobile-responsive styles for user interface */
|
||||
.container {
|
||||
width: 95% !important;
|
||||
margin: 10px auto !important;
|
||||
padding: 15px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 12px 12px 18px !important;
|
||||
border-radius: 0 !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
@@ -3414,7 +3449,7 @@
|
||||
display: grid !important;
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 15px !important;
|
||||
padding: 10px 0 !important;
|
||||
padding: 10px 0 0 !important;
|
||||
overflow-x: visible !important;
|
||||
}
|
||||
|
||||
@@ -3431,12 +3466,12 @@
|
||||
|
||||
/* Modal improvements for mobile */
|
||||
.modal-content {
|
||||
width: 95% !important;
|
||||
max-width: 500px !important;
|
||||
margin: 20px auto !important;
|
||||
width: calc(100vw - 16px) !important;
|
||||
max-width: none !important;
|
||||
margin: 8px auto !important;
|
||||
max-height: 85vh !important;
|
||||
overflow-y: auto !important;
|
||||
padding: 20px !important;
|
||||
padding: 16px !important;
|
||||
}
|
||||
|
||||
/* Button improvements */
|
||||
|
||||
@@ -369,6 +369,22 @@
|
||||
animation: items-loader-slide 1.05s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.items-loading-indicator {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
min-height: 120px;
|
||||
height: auto;
|
||||
padding: 14px 10px;
|
||||
scroll-snap-align: none;
|
||||
}
|
||||
|
||||
.items-loading-indicator .loading-track {
|
||||
width: min(240px, 82%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes items-loader-slide {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(260%); }
|
||||
@@ -1221,9 +1237,11 @@
|
||||
|
||||
/* Mobile-responsive styles for admin interface */
|
||||
.admin-content-container {
|
||||
width: 95% !important;
|
||||
margin: 10px auto !important;
|
||||
padding: 15px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 12px 12px 18px !important;
|
||||
box-sizing: border-box !important;
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
@@ -1347,11 +1365,12 @@
|
||||
|
||||
/* Modal improvements for admin */
|
||||
.modal-content {
|
||||
width: 95% !important;
|
||||
max-width: 500px !important;
|
||||
margin: 20px auto !important;
|
||||
width: calc(100vw - 16px) !important;
|
||||
max-width: none !important;
|
||||
margin: 8px auto !important;
|
||||
max-height: 85vh !important;
|
||||
overflow-y: auto !important;
|
||||
padding: 16px !important;
|
||||
}
|
||||
|
||||
/* Admin card improvements */
|
||||
@@ -1510,9 +1529,11 @@
|
||||
/* Mobile-responsive styles for admin interface */
|
||||
@media screen and (max-width: 768px) {
|
||||
.admin-content-container {
|
||||
width: 95% !important;
|
||||
margin: 10px auto !important;
|
||||
padding: 15px !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 12px 12px 18px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
@@ -1599,12 +1620,12 @@
|
||||
|
||||
/* Modal improvements for admin */
|
||||
.modal-content {
|
||||
width: 95% !important;
|
||||
max-width: 500px !important;
|
||||
margin: 20px auto !important;
|
||||
width: calc(100vw - 16px) !important;
|
||||
max-width: none !important;
|
||||
margin: 8px auto !important;
|
||||
max-height: 85vh !important;
|
||||
overflow-y: auto !important;
|
||||
padding: 20px !important;
|
||||
padding: 16px !important;
|
||||
}
|
||||
|
||||
/* Button improvements */
|
||||
@@ -1792,9 +1813,11 @@
|
||||
}
|
||||
|
||||
.admin-content-container {
|
||||
width: 95%;
|
||||
margin: 10px auto;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: 12px 12px 18px;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@@ -1808,12 +1831,13 @@
|
||||
|
||||
/* Better modal sizing for mobile */
|
||||
.modal-content {
|
||||
width: 95% !important;
|
||||
width: calc(100vw - 16px) !important;
|
||||
max-width: none !important;
|
||||
margin: 10px auto !important;
|
||||
margin: 8px auto !important;
|
||||
max-height: 90vh !important;
|
||||
overflow-y: auto !important;
|
||||
-webkit-overflow-scrolling: touch !important;
|
||||
padding: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3366,8 +3390,18 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
return;
|
||||
}
|
||||
|
||||
const distanceToEnd = itemsContainer.scrollWidth - (itemsContainer.scrollLeft + itemsContainer.clientWidth);
|
||||
const prefetchThreshold = Math.max(260, itemsContainer.clientWidth * 1.4);
|
||||
const styles = window.getComputedStyle(itemsContainer);
|
||||
const isMobileLayout =
|
||||
window.matchMedia('(max-width: 768px)').matches ||
|
||||
styles.display === 'grid' ||
|
||||
styles.flexDirection === 'column';
|
||||
|
||||
const distanceToEnd = isMobileLayout
|
||||
? itemsContainer.scrollHeight - (itemsContainer.scrollTop + itemsContainer.clientHeight)
|
||||
: itemsContainer.scrollWidth - (itemsContainer.scrollLeft + itemsContainer.clientWidth);
|
||||
const prefetchThreshold = isMobileLayout
|
||||
? Math.max(220, itemsContainer.clientHeight * 0.9)
|
||||
: Math.max(260, itemsContainer.clientWidth * 1.4);
|
||||
if (distanceToEnd > prefetchThreshold) {
|
||||
return;
|
||||
}
|
||||
@@ -3729,6 +3763,12 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
const itemsContainer = ensureMainAdminItemsSentinel();
|
||||
if (!itemsContainer) return;
|
||||
|
||||
const styles = window.getComputedStyle(itemsContainer);
|
||||
const isMobileLayout =
|
||||
window.matchMedia('(max-width: 768px)').matches ||
|
||||
styles.display === 'grid' ||
|
||||
styles.flexDirection === 'column';
|
||||
|
||||
if (mainAdminItemsObserver) {
|
||||
mainAdminItemsObserver.disconnect();
|
||||
mainAdminItemsObserver = null;
|
||||
@@ -3759,7 +3799,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
||||
}, {
|
||||
root: itemsContainer,
|
||||
threshold: 0.15,
|
||||
rootMargin: '0px 900px 0px 0px'
|
||||
rootMargin: isMobileLayout ? '0px 0px 900px 0px' : '0px 900px 0px 0px'
|
||||
});
|
||||
|
||||
mainAdminItemsObserver.observe(mainAdminItemsSentinel);
|
||||
|
||||
@@ -191,29 +191,7 @@ setup_scheduled_jobs() {
|
||||
fi
|
||||
|
||||
local update_line backup_line
|
||||
local slot_seed slot_hash slot_bucket slot_hour slot_minute
|
||||
local update_window_minutes update_window_hours
|
||||
|
||||
update_window_minutes="${INVENTAR_UPDATE_WINDOW_MINUTES:-120}"
|
||||
if ! [[ "$update_window_minutes" =~ ^[0-9]+$ ]]; then
|
||||
update_window_minutes="120"
|
||||
fi
|
||||
if [ "$update_window_minutes" -lt 15 ]; then
|
||||
update_window_minutes="15"
|
||||
fi
|
||||
|
||||
update_window_hours=$(( (update_window_minutes + 59) / 60 ))
|
||||
if [ "$update_window_hours" -lt 1 ]; then
|
||||
update_window_hours=1
|
||||
fi
|
||||
|
||||
slot_seed="$(cat /etc/machine-id 2>/dev/null || hostname)|${INVENTAR_INSTANCE_ID:-${HOSTNAME:-unknown}}|$SCRIPT_DIR|nightly-update"
|
||||
slot_hash="$(printf '%s' "$slot_seed" | sha256sum | awk '{print $1}')"
|
||||
slot_bucket=$((16#${slot_hash:0:8} % update_window_minutes))
|
||||
slot_hour=$((3 + (slot_bucket / 60)))
|
||||
slot_minute=$((slot_bucket % 60))
|
||||
|
||||
update_line="$slot_minute $slot_hour * * * cd $SCRIPT_DIR && INVENTAR_UPDATE_MODE=auto ./update.sh >> $SCRIPT_DIR/logs/update.log 2>&1"
|
||||
update_line="0 3 * * * cd $SCRIPT_DIR && ./update.sh >> $SCRIPT_DIR/logs/update.log 2>&1"
|
||||
backup_line="30 2 * * * cd $SCRIPT_DIR && ./backup.sh --mode auto >> $SCRIPT_DIR/logs/backup.log 2>&1"
|
||||
|
||||
local existing_cron
|
||||
@@ -234,7 +212,7 @@ setup_scheduled_jobs() {
|
||||
fi
|
||||
|
||||
echo "Nightly backup scheduled at 02:30"
|
||||
printf 'Nightly auto-update scheduled at %02d:%02d (deterministic instance slot, %s-minute window)\n' "$slot_hour" "$slot_minute" "$update_window_minutes"
|
||||
echo "Nightly auto-update scheduled at 03:00"
|
||||
}
|
||||
|
||||
ensure_tls_certificates() {
|
||||
|
||||
@@ -15,9 +15,6 @@ APP_IMAGE_ASSET_PREFIX="inventarsystem-image-"
|
||||
ENV_FILE="$PROJECT_DIR/.docker-build.env"
|
||||
APP_IMAGE_REPO="ghcr.io/aiirondev/legendary-octo-garbanzo"
|
||||
DIST_DIR="$PROJECT_DIR/dist"
|
||||
LOCK_FILE="$PROJECT_DIR/.update.lock"
|
||||
|
||||
DEFAULT_UPDATE_BUFFER_MINUTES="${INVENTAR_UPDATE_BUFFER_MINUTES:-90}"
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
chmod 777 "$LOG_DIR" 2>/dev/null || true
|
||||
@@ -26,74 +23,6 @@ log_message() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
safe_int() {
|
||||
local raw="$1"
|
||||
if [[ "$raw" =~ ^[0-9]+$ ]]; then
|
||||
echo "$raw"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
acquire_update_lock() {
|
||||
exec 9>"$LOCK_FILE"
|
||||
if ! flock -n 9; then
|
||||
log_message "Another update process is already running. Exiting."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
compute_update_buffer_seconds() {
|
||||
if [ "${INVENTAR_SKIP_UPDATE_BUFFER:-0}" = "1" ]; then
|
||||
echo "0"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Manual interactive runs should not wait by default.
|
||||
if [ -t 1 ] && [ "${INVENTAR_FORCE_UPDATE_BUFFER:-0}" != "1" ]; then
|
||||
echo "0"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local explicit_seconds
|
||||
explicit_seconds="$(safe_int "${INVENTAR_UPDATE_BUFFER_SECONDS:-0}")"
|
||||
if [ "$explicit_seconds" -gt 0 ]; then
|
||||
echo "$explicit_seconds"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local window_minutes window_seconds
|
||||
window_minutes="$(safe_int "$DEFAULT_UPDATE_BUFFER_MINUTES")"
|
||||
if [ "$window_minutes" -le 0 ]; then
|
||||
echo "0"
|
||||
return 0
|
||||
fi
|
||||
|
||||
window_seconds=$((window_minutes * 60))
|
||||
|
||||
local machine_id instance_id seed hash_hex hash_dec
|
||||
machine_id="$(cat /etc/machine-id 2>/dev/null || hostname)"
|
||||
instance_id="${INVENTAR_INSTANCE_ID:-${HOSTNAME:-unknown}}"
|
||||
seed="$machine_id|$instance_id|$PROJECT_DIR|update-buffer"
|
||||
|
||||
hash_hex="$(printf '%s' "$seed" | sha256sum | awk '{print $1}')"
|
||||
hash_dec=$((16#${hash_hex:0:8}))
|
||||
|
||||
echo $((hash_dec % window_seconds))
|
||||
}
|
||||
|
||||
apply_update_buffer_if_needed() {
|
||||
local delay_seconds
|
||||
delay_seconds="$(compute_update_buffer_seconds)"
|
||||
if [ "$delay_seconds" -le 0 ]; then
|
||||
log_message "Update buffer: no delay applied"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_message "Update buffer active: delaying start by ${delay_seconds}s to reduce cross-instance peak load"
|
||||
sleep "$delay_seconds"
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
log_message "ERROR: Required command not found: $1"
|
||||
@@ -466,9 +395,6 @@ verify_stack_health() {
|
||||
}
|
||||
|
||||
main() {
|
||||
acquire_update_lock
|
||||
apply_update_buffer_if_needed
|
||||
|
||||
ensure_runtime_dependencies
|
||||
ensure_tls_certificates
|
||||
ensure_nginx_config_mount_source
|
||||
|
||||
Reference in New Issue
Block a user