# ctx.exitAll()

Завершает текущий поток событий и все последующие потоки событий, вызванные в рамках той же диспетчеризации событий. Часто используется, когда необходимо немедленно прервать все потоки событий в рамках текущего события из-за глобальной ошибки или сбоя проверки прав доступа.

## Применимые сценарии

`ctx.exitAll()` обычно используется в контекстах выполнения JS, когда необходимо **одновременно прервать текущий поток событий и последующие потоки событий, вызванные этим событием**:

| Сценарий | Описание |
|------|------|
| **Поток событий** | Ошибка валидации основного потока (например, недостаточно прав), требуется прервать основной поток и все еще не выполненные последующие потоки в рамках того же события. |
| **Правила связей** | Когда валидация связи не пройдена, текущая связь и последующие связи, вызванные тем же событием, должны быть прекращены. |
| **События действий** | Сбой предварительной валидации действия (например, проверка прав перед удалением), требуется предотвратить основное действие и последующие шаги. |

> Отличие от `ctx.exit()`: `ctx.exit()` завершает только текущий поток событий; `ctx.exitAll()` завершает текущий поток событий и любые **невыполненные** последующие потоки событий в той же диспетчеризации.

## Определение типа

```ts
exitAll(): never;
```

Вызов `ctx.exitAll()` выбрасывает внутреннее исключение `FlowExitAllException`, которое перехватывается движком потоков событий для остановки текущего экземпляра потока и последующих потоков в рамках того же события. После вызова оставшиеся инструкции в текущем JS-коде не будут выполнены.

## Сравнение с ctx.exit()

| Метод | Область действия |
|------|----------|
| `ctx.exit()` | Завершает только текущий поток событий; последующие потоки событий не затрагиваются. |
| `ctx.exitAll()` | Завершает текущий поток событий и прерывает последующие потоки событий, выполняемые **последовательно** в рамках того же события. |

## Описание режима выполнения

- **Последовательное выполнение (sequential)**: Потоки событий в рамках одного события выполняются по порядку. Если какой-либо поток вызывает `ctx.exitAll()`, последующие потоки не будут выполнены.
- **Параллельное выполнение (parallel)**: Потоки событий в рамках одного события выполняются параллельно. Вызов `ctx.exitAll()` в одном потоке не прервет другие параллельные потоки (так как они независимы).

## Примеры

### Завершение всех потоков событий при сбое проверки прав

```ts
// Прервать основной поток и последующие потоки при недостаточности прав
if (!hasPermission(ctx)) {
  ctx.notification.error({ message: 'Нет прав для выполнения операции' });
  ctx.exitAll();
}
```

### Завершение при сбое глобальной предварительной валидации

```ts
// Пример: если перед удалением обнаружено, что связанные данные нельзя удалять,
// необходимо предотвратить основной поток и последующие действия
const canDelete = await checkDeletable(ctx.model?.getValue?.());
if (!canDelete) {
  ctx.message.error('Невозможно удалить: существуют связанные данные');
  ctx.exitAll();
}
```

### Выбор между ctx.exit() и ctx.exitAll()

```ts
// Нужно выйти только из текущего потока событий -> используйте ctx.exit()
if (!params.valid) {
  ctx.message.error('Недопустимые параметры');
  ctx.exit();  // Последующие потоки событий не затрагиваются
}

// Нужно завершить все последующие потоки событий в рамках текущего события -> используйте ctx.exitAll()
if (!ctx.model?.context?.getPermission?.()) {
  ctx.notification.warning({ message: 'Недостаточно прав' });
  ctx.exitAll();  // И основной поток, и последующие потоки того же события будут завершены
}
```

### Уведомление перед завершением

```ts
if (!isValidInput(ctx.form?.getValues?.())) {
  ctx.message.warning('Пожалуйста, сначала исправьте ошибки в форме');
  ctx.exitAll();
}
```

## Примечания

- После вызова `ctx.exitAll()` последующий код в текущем JS не будет выполнен. Рекомендуется объяснить причину пользователю через `ctx.message`, `ctx.notification` или модальное окно перед вызовом.
- В бизнес-коде обычно не нужно перехватывать `FlowExitAllException`; позвольте движку потоков событий обработать его.
- Если вам нужно остановить только текущий поток событий, не затрагивая последующие, используйте `ctx.exit()`.
- В параллельном режиме `ctx.exitAll()` завершает только текущий поток событий и не прерывает другие параллельные потоки.

## Связанные разделы

- [ctx.exit()](./exit.md): Завершает только текущий поток событий
- [ctx.message](./message.md): Информационные сообщения
- [ctx.modal](./modal.md): Модальное окно подтверждения