Ваше приложение работает идеально, пока… не ломается всё
Вы когда-нибудь замечали, что в production всё работает идеально ровно до того момента, пока не случается что-то из ряда вон? База данных зависает на секунду — и весь фронтенд превращается в белый экран. API стороннего сервиса отвечает 500-й ошибкой — и пользователи видят «Что-то пошло не так». Знакомо?
В классическом тестировании мы проверяем: «Всё работает? Ок, релизим». Но мир распределённых систем и микросервисов (а JavaScript сегодня правит и бэкендом, и фронтендом) жесток. Он требует инженерного цинизма. Именно здесь на сцену выходит Chaos Engineering — дисциплина, которая учит нас ломать систему намеренно, чтобы сделать её сильнее.
Давайте разберёмся, как применять Chaos Engineering в JS-приложениях (будь то Node.js бэкенд, React-фронтенд или Next.js сайт), и напишем код, который вы сможете запустить уже сегодня.
Что такое Chaos Engineering простыми словами?
Chaos Engineering (инжиниринг хаоса) — это практика экспериментов над распределённой системой, чтобы выявить её слабые места до того, как это сделают реальные пользователи. Netflix, например, придумал Chaos Monkey — сервис, который случайным образом убивает production-серверы в рабочее время. Звучит безумно? Да. Работает? Ещё как.
Основная идея: вместо того чтобы бояться сбоев, мы их провоцируем в контролируемой среде. Это позволяет:
- Найти скрытые баги в логике обработки ошибок
- Проверить, корректно ли приложение восстанавливается после падения
- Убедиться, что мониторинг и алертинг работают
- Повысить культуру resilience (отказоустойчивости) в команде
Для JavaScript-разработчика это особенно актуально: фронтенд-приложения зависят от сотен API, а Node.js-сервисы часто работают в облаке, где виртуальные машины могут умереть в любой момент.
Инструменты для Chaos Engineering в JavaScript
Не нужно сразу запускать Gremlin в production. Начните с малого — с локальных экспериментов. Вот что нам пригодится:
- Gremlin — мощная платформа с SDK для Node.js. Позволяет эмулировать задержки, сбои CPU, убийство процессов.
- Chaos Monkey от Netflix (часть Spinnaker) — для тех, кто уже живёт в микросервисной архитектуре.
- node-chaos — легковесная библиотека для внедрения хаоса в Node.js приложения.
- Собственные скрипты — иногда проще написать 20 строк кода, чем разворачивать тяжёлый инструмент.
Мы пойдём третьим путём и напишем свой маленький «хаос-инженер» на чистом JavaScript.
Практика: пишем Chaos Experiment для Node.js
Шаг 1. Сценарий: «Внезапная задержка API»
Представим, что у нас есть Express-сервер, который ходит в базу данных. Внезапно БД начинает отвечать с задержкой в 5 секунд. Как поведёт себя клиентский код?
Создадим middleware для Express, который с вероятностью 30% будет добавлять случайную задержку (от 1 до 10 секунд):
// chaos-middleware.js
const chaosMiddleware = (req, res, next) => {
// Вероятность сбоя: 30%
const shouldFail = Math.random() < 0.3;
if (shouldFail) {
// Случайная задержка от 1000 до 10000 мс
const delay = Math.floor(Math.random() * 9000) + 1000;
console.warn(`[CHAOS] Injecting latency: ${delay}ms for ${req.path}`);
setTimeout(() => {
// С вероятностью 10% — убиваем запрос ошибкой 500
if (Math.random() < 0.1) {
return res.status(500).json({ error: 'Chaos induced failure' });
}
next();
}, delay);
} else {
next();
}
};
module.exports = chaosMiddleware;
Подключаем middleware к приложению:
// app.js
const express = require('express');
const chaosMiddleware = require('./chaos-middleware');
const app = express();
// Включаем хаос только для эндпоинта /api/data
app.use('/api/data', chaosMiddleware);
app.get('/api/data', (req, res) => {
// Симуляция работы с БД
res.json({ message: 'Data from database', timestamp: Date.now() });
});
app.listen(3000, () => console.log('Server running on port 3000'));
Теперь при каждом запросе к /api/data есть шанс получить либо долгий ответ, либо 500-ю ошибку. Если ваш фронтенд написан на React — это отличный способ проверить, как работают retry-логика и fallback UI.
Шаг 2. Тестируем клиентскую часть (React)
Напишем простой компонент, который делает запрос к нашему «хаотичному» API и корректно обрабатывает ошибки и таймауты:
// DataFetcher.jsx
import { useState, useEffect } from 'react';
const DataFetcher = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchData = async () => {
setLoading(true);
setError(null);
try {
// Важно: устанавливаем таймаут на запрос
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 8000); // 8 секунд — предел
const response = await fetch('/api/data', { signal: controller.signal });
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
if (err.name === 'AbortError') {
setError('Request timed out. Please try again.');
} else {
setError(`Failed to fetch data: ${err.message}`);
}
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return <div>Data: {JSON.stringify(data)}</div>;
};
export default DataFetcher;
Запустите сервер с middleware хаоса и посмотрите, как компонент реагирует на задержки и ошибки. Если вы увидите, что UI «зависает» на 10 секунд без индикации — значит, нужно улучшать код.
Продвинутые сценарии Chaos Engineering
Задержки и 500-е ошибки — это только начало. Настоящий хаос многогранен. Вот ещё три сценария, которые стоит попробовать:
1. Убийство процесса (Node.js)
Эмулируем ситуацию, когда ваш сервис упал из-за OutOfMemory. В production