{
  "schemaVersion": 1,
  "id": "5e1f9c3d-2a7b-4d6e-9f08-3c4b5a6d7e81",
  "name": "Урок: ошибки и повторы",
  "description": "Шаг с «Продолжать при ошибке», перехват ошибки по коду и повтор ненадёжного шага до maxAttempts раз с паузой",
  "variables": [
    {
      "name": "maxAttempts",
      "type": "number",
      "default": 3,
      "isArgument": true
    },
    {
      "name": "failUntil",
      "type": "number",
      "default": 3,
      "isArgument": true
    },
    {
      "name": "attempt",
      "type": "number",
      "default": 0,
      "isArgument": false
    },
    {
      "name": "done",
      "type": "boolean",
      "default": false,
      "isArgument": false
    },
    {
      "name": "settings",
      "type": "string",
      "default": "",
      "isArgument": false
    },
    {
      "name": "error",
      "type": "object",
      "default": null,
      "isArgument": false
    }
  ],
  "steps": [
    {
      "id": "s_read0001",
      "type": "file.readText",
      "displayName": "Прочитать settings.txt (файла может не быть)",
      "continueOnError": true,
      "props": {
        "path": "settings.txt",
        "encoding": "utf-8"
      },
      "out": {
        "text": "settings"
      }
    },
    {
      "id": "s_log00001",
      "type": "control.log",
      "props": {
        "level": "info",
        "message": "Настройки: {{ settings === '' ? 'файла нет, берём значения по умолчанию' : settings }}"
      }
    },
    {
      "id": "s_try00001",
      "type": "control.tryCatch",
      "displayName": "Файл, которого нет",
      "props": {
        "errorVariable": "error"
      },
      "children": {
        "try": [
          {
            "id": "s_read0002",
            "type": "file.readText",
            "props": {
              "path": "нет-такого-файла.txt",
              "encoding": "utf-8"
            },
            "out": {
              "text": "settings"
            }
          }
        ],
        "catch": [
          {
            "id": "s_code0001",
            "type": "control.if",
            "props": {
              "condition": "error.code === 'FileNotFound'"
            },
            "children": {
              "then": [
                {
                  "id": "s_logfnf01",
                  "type": "control.log",
                  "props": {
                    "level": "warn",
                    "message": "Ожидаемая ошибка {{ error.code }}: {{ error.message }}"
                  }
                }
              ],
              "else": [
                {
                  "id": "s_rethrow1",
                  "type": "control.throw",
                  "props": {
                    "message": "Непредвиденная ошибка {{ error.code }}: {{ error.message }}"
                  }
                }
              ]
            }
          }
        ],
        "finally": [
          {
            "id": "s_logfin01",
            "type": "control.log",
            "props": {
              "level": "info",
              "message": "Блок finally выполняется всегда"
            }
          }
        ]
      }
    },
    {
      "id": "s_while001",
      "type": "control.while",
      "displayName": "Повторять, пока не получится",
      "props": {
        "condition": "!done && attempt < maxAttempts",
        "maxIterations": 10
      },
      "children": {
        "body": [
          {
            "id": "s_attempt1",
            "type": "control.assign",
            "displayName": "Следующая попытка",
            "props": {
              "variable": "attempt",
              "value": "attempt + 1"
            }
          },
          {
            "id": "s_try00002",
            "type": "control.tryCatch",
            "displayName": "Попытка",
            "props": {
              "errorVariable": "error"
            },
            "children": {
              "try": [
                {
                  "id": "s_flaky001",
                  "type": "control.if",
                  "displayName": "Ненадёжный шаг",
                  "props": {
                    "condition": "attempt < failUntil"
                  },
                  "children": {
                    "then": [
                      {
                        "id": "s_throw001",
                        "type": "control.throw",
                        "props": {
                          "message": "Сервис недоступен (попытка {{ attempt }})"
                        }
                      }
                    ]
                  }
                },
                {
                  "id": "s_done0001",
                  "type": "control.assign",
                  "props": {
                    "variable": "done",
                    "value": "true"
                  }
                },
                {
                  "id": "s_logok001",
                  "type": "control.log",
                  "props": {
                    "level": "info",
                    "message": "Попытка {{ attempt }}: успешно"
                  }
                }
              ],
              "catch": [
                {
                  "id": "s_logerr01",
                  "type": "control.log",
                  "props": {
                    "level": "warn",
                    "message": "Попытка {{ attempt }} не удалась: {{ error.message }}"
                  }
                },
                {
                  "id": "s_delay001",
                  "type": "control.delay",
                  "displayName": "Пауза перед повтором",
                  "props": {
                    "ms": 1000
                  }
                }
              ]
            }
          }
        ]
      }
    },
    {
      "id": "s_result01",
      "type": "control.if",
      "displayName": "Получилось?",
      "props": {
        "condition": "done"
      },
      "children": {
        "then": [
          {
            "id": "s_logend01",
            "type": "control.log",
            "props": {
              "level": "info",
              "message": "Готово с попытки {{ attempt }} из {{ maxAttempts }}"
            }
          }
        ],
        "else": [
          {
            "id": "s_throw002",
            "type": "control.throw",
            "props": {
              "message": "Не получилось: все попытки ({{ maxAttempts }}) неудачны"
            }
          }
        ]
      }
    }
  ]
}
