awesome-everything EN
↑ Обратно к восхождению

Архитектура бэкенда

Middleware и DI: чтение кода и конфигурации

Суть Чтение реальных сниппетов Express и NestJS — баг порядка middleware, singleton с состоянием запроса, издержки bubbling request-scope и цикл зависимостей — и выбор фикса с наибольшим рычагом.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Баги middleware и DI диагностируются в коде связывания и порядке регистрации, а не в бизнес-логике. Прочитайте каждый сниппет, предскажите, что сломается под нагрузкой, и выберите фикс, к которому senior-инженер тянется первым.

Цель

Отработайте цикл, который запускает каждый инцидент middleware/DI: прочитать порядок pipeline или связывание, предсказать сбой (утёкший ответ, межпользовательская гонка данных, пересборка графа на каждый запрос, неразрешимый цикл) и выбрать структурный фикс вместо заплатки.

Сниппет 1 — порядок middleware

const app = express();

app.use(expensiveBodyParser());   // парсит + буферизует всё тело
app.use(rateLimit({ max: 100 })); // отклоняет 101-й запрос
app.use(authenticate);            // проверяет bearer-токен
app.use('/api', apiRouter);
Викторина

Поток неаутентифицированных запросов с большими телами разгоняет CPU до 100%. Что не так с этим порядком и каков фикс?

Сниппет 2 — поле в singleton

@Injectable()                     // scope по умолчанию: singleton
export class AuditService {
  private currentUser?: User;     // ставится на запрос, читается позже

  setUser(u: User) { this.currentUser = u; }

  record(action: string) {
    log(`${this.currentUser?.id} did ${action}`);
  }
}
Викторина

Под конкурентной нагрузкой журнал аудита приписывает действия не тому пользователю. Почему и каков самый чистый фикс?

Сниппет 3 — request-scoped логгер

@Injectable({ scope: Scope.REQUEST })   // один экземпляр на запрос
export class ContextLogger { /* хранит request id */ }

@Injectable()                            // задуман как singleton
export class PaymentService {
  constructor(private log: ContextLogger) {}   // внедряет request-scoped зависимость
}
// AppController внедряет PaymentService, OrderService внедряет PaymentService...
Викторина

После этого изменения нагрузочный тест показывает повышенные аллокации и латентность во многих несвязанных сервисах. Почему?

Сниппет 4 — цикл зависимостей

@Injectable()
export class AuthService {
  constructor(private users: UserService) {}   // нужен UserService
}

@Injectable()
export class UserService {
  constructor(private auth: AuthService) {}     // нужен AuthService
}
Викторина

Контейнер бросает 'cannot resolve dependencies'. Какова первопричина и структурно правильный фикс?

Итог

Каждый инцидент middleware/DI читается в связывании, а не в логике. Порядок middleware — рычаг стоимости и безопасности: ставьте дешёвые отказы (rate limit, auth) перед дорогой работой вроде парсинга тела. Singleton должен быть без состояния относительно запроса; хранение полей на запрос гонит данные между конкурентными пользователями, поэтому передавайте значение аргументом. Request scope всплывает вверх по цепочке внедрения и пересобирает подграф на запрос, так что тянитесь к нему только при реальной необходимости. А у цикла зависимостей нет топологического порядка — структурный фикс в выносе общего третьего класса, а не в подавлении резолвера через forwardRef.

Продолжить восхождение ↑Middleware и DI: соберите тестируемый сервис
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.