Укрепление эксплуатации: healthcheck'и, лимиты ресурсов, логи, self-hosted шрифты, smoke-проверка в CI
Deploy / deploy (push) Failing after 0s

This commit is contained in:
2026-11-10 00:59:14 +05:00
parent 6746d89233
commit c47391b6db
32 changed files with 375 additions and 18 deletions
+1 -3
View File
@@ -5,9 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>./blocks — cacto</title>
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/css/fonts.css" />
<link rel="stylesheet" href="/css/theme.css" />
<link rel="stylesheet" href="/css/arcade.css" />
</head>
+149
View File
@@ -0,0 +1,149 @@
/* Self-hosted JetBrains Mono (сабсеты cyrillic/cyrillic-ext/latin/latin-ext).
Источник: Google Fonts, OFL-лицензия. Заменяет fonts.googleapis.com —
убирает внешнюю зависимость и лишние хосты из CSP. */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/vendor/fonts/jbmono-400-cyrillic-ext.woff2') format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/vendor/fonts/jbmono-400-cyrillic.woff2') format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/vendor/fonts/jbmono-400-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/vendor/fonts/jbmono-400-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/vendor/fonts/jbmono-500-cyrillic-ext.woff2') format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/vendor/fonts/jbmono-500-cyrillic.woff2') format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/vendor/fonts/jbmono-500-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/vendor/fonts/jbmono-500-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/vendor/fonts/jbmono-600-cyrillic-ext.woff2') format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/vendor/fonts/jbmono-600-cyrillic.woff2') format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/vendor/fonts/jbmono-600-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/vendor/fonts/jbmono-600-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/vendor/fonts/jbmono-700-cyrillic-ext.woff2') format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/vendor/fonts/jbmono-700-cyrillic.woff2') format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/vendor/fonts/jbmono-700-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/vendor/fonts/jbmono-700-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
+1 -3
View File
@@ -5,9 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>./tanks — cacto</title>
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/css/fonts.css" />
<link rel="stylesheet" href="/css/theme.css" />
<link rel="stylesheet" href="/css/game.css" />
</head>
+1 -3
View File
@@ -13,9 +13,7 @@
<meta property="og:image" content="https://cactoz.su/assets/og.png" />
<meta name="twitter:card" content="summary_large_image" />
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/css/fonts.css" />
<link rel="stylesheet" href="/css/theme.css" />
<link rel="stylesheet" href="/css/resume.css" />
</head>
+1 -3
View File
@@ -5,9 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>./invaders — cacto</title>
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/css/fonts.css" />
<link rel="stylesheet" href="/css/theme.css" />
<link rel="stylesheet" href="/css/arcade.css" />
</head>
+9
View File
@@ -12,6 +12,15 @@ export class Network {
const msg = JSON.parse(event.data);
this._emit(msg.type, msg.payload);
});
// NAT-таблицы на промежуточных роутерах гаснут раньше, чем серверный
// idleTimeout (300с) — application-ping раз в 25с держит соединение живым
// и на случай обрыва держим интервал заметно меньше таймаута.
setInterval(() => {
if (this.socket.readyState === WebSocket.OPEN) {
this.send(ClientMessage.PING);
}
}, 25000);
}
on(type, handler) {
+2
View File
@@ -1,6 +1,7 @@
// Типы сообщений из TZ.md, раздел 5.
export const ClientMessage = {
HELLO: 'hello',
PING: 'ping',
LOBBY_LIST_ROOMS: 'lobby.list_rooms',
LOBBY_CREATE_ROOM: 'lobby.create_room',
LOBBY_JOIN_ROOM: 'lobby.join_room',
@@ -11,6 +12,7 @@ export const ClientMessage = {
export const ServerMessage = {
HELLO_ACK: 'hello.ack',
PONG: 'pong',
ERROR: 'error',
LOBBY_ROOMS: 'lobby.rooms',
LOBBY_ROOM_JOINED: 'lobby.room_joined',
+1 -3
View File
@@ -7,9 +7,7 @@
<meta name="description" content="Проекты Гаммеля Дмитрия: home automation platform и этот сайт." />
<link rel="canonical" href="https://cactoz.su/projects" />
<link rel="icon" type="image/svg+xml" href="/assets/cactus-logo.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/css/fonts.css" />
<link rel="stylesheet" href="/css/theme.css" />
<link rel="stylesheet" href="/css/projects.css" />
</head>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.