# Алгоритм работы Python-фреймворка

Запускаемый с помощью Планировщика Windows скрипт Python-фреймворка должен следовать следующему алгоритму:

1. Выполнить HTTP POST запрос к скрипту `/api/robot/heartbeat` Оркестратора. Передать в параметрах:
   1. GUID данного Робота (RobotGUID),
   2. имя компьютера (Machine),
   3. IP адрес машины (IP),
   4. MAC адрес машины (MAC),
   5. текущий статус Робота (Status),
   6. GUID исполняемой в данный момент Работы (JobGUID),
   7. название исполняемой в данный момент Работы (JobName),
   8. тип Работы (JobType, всегда должен иметь тип Orchestrated, значение 1).

Выходные данные (в формате JSON):

* HeartbeatErrorCode,
* ErrorText,
* HasNewJob.

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

Справочник статусов Роботов:

```
Status_Disconnected = 0; # робот отключен
Status_Unlicensed     = 1; # робот не лицензирован
Status_Ready        = 2; # робот не выполняет работы и готов к приему новых работ
Status_Working    = 3; # робот выполняет текущую работу
```

Справочник значений ErrorCode:

```
HeartbeatErrorCode_NoError = 0;  # нет ошибок
HeartbeatErrorCode_RobotNotFound = 101;  # робот с указанным GUID не найден
HeartbeatErrorCode_JobAborting = 10;   # оркестратор запросил жесткую остановку данного сценария (Abort)
HeartbeatErrorCode_JobStopping = 20;   # оркестратор запросил мягкую остановку данного сценария (Stop)
```

Справочник значений HasNewJob:

```
HasNewJob_NoJob = 0 # для данного робота отсутствуют новые работы
HasNewJob_JobFound = 1 # для данного робота есть новые работы, которые необходимо получить с помощью вызова ConsumeNextJob
```

При первом запуске скрипта необходимо передать значение `Status = 2` (Status\_Ready). Также при первом запуске, когда название и GUID выполняемой работы ещё неизвестны, данные поля могут оставаться пустыми.

Пример вызова:

```
import requests
import base64
import json

from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
host = 'http://192.168.1.111:4500' #хост оркестратора
robot_guid = 'da8bc2f0-8065-4385-b867-405e66b8e151' #GUID робота
headers = {
    'Authorization': 'Basic ' + base64.b64encode(robot_guid.encode('utf-8')).decode('utf-8')
}
req = {
    'RobotGUID': robot_guid   #GUID робота
    'Machine': robot_machine   #Имя машины
    'IP': robot_ip   #IP адрес робота
    'MAC': robot_mac   #MAC адрес робота
    'Status': 2   #статус робота
    'JobGUID': ''  #GUID работы
    'JobName': ''   #название выполняемого скрипта, т.е. python_script_name далее по тексту
    'JobType': 1   #тип работы, всегда значение 1
}
r = requests.post(host + '/api/robot/heartbeat', data=req, headers=headers, verify=False)
heartbeat_results = json.loads(r.text)
print(heartbeat_results ['HeartbeatErrorCode'])
print(heartbeat_results ['ErrorText'])
print(heartbeat_results ['HasNewJob'])
```

2. В случае если получен ответ `HasNewJob == 0`, завершить выполнение скрипта фреймворка и выйти из учетной записи Windows с помощью Log off.\
   \
   В случае, если получен ответ `HasNewJob == 1`, выполнить HTTP POST запрос к скрипту `/api/robot/consumeNextJob` Оркестратора.\
   \
   Входные данные:

   1. GUID Робота (RobotGUID),
   2. текущий статус Робота (Status).

   \
   Выходные данные (в формате JSON):

   1. ConsumeJobErrorCode,
   2. ErrorText,
   3. Job,
   4. ProcessVersion,
   5. Task.

   Справочник значений ConsumeJobErrorCode:\
   \
   `ConsumeJobErrorCode = 0; # нет ошибок`\
   `ConsumeJobErrorCode = 101; # робот с указанным GUID не найден`\
   `ConsumeJobErrorCode = 102; # новая работа не найдена`\
   \
   Пример вызова:\
   \
   `import requests`\
   `import base64`\
   `import json`\
   \
   `from requests.packages.urllib3.exceptions import InsecureRequestWarning`\
   `requests.packages.urllib3.disable_warnings(InsecureRequestWarning)`\
   \
   `host = 'http://192.168.1.111:4500' #хост оркестратора`\
   `robot_guid = 'da8bc2f0-8065-4385-b867-405e66b8e151' #GUID робота`\
   \
   `headers = {`\
   `'Authorization': 'Basic ' + base64.b64encode(robot_guid.encode('utf-8')).decode('utf-8')`\
   `}`\
   \
   `cnj = {`\
   `'RobotGUID': robot_guid #GUID робота`\
   `}`\
   \
   `r = requests.post(host + '/api/robot/consumeNextJob', data=cnj, headers=headers, verify=False)`\
   `consume_result = json.loads(r.text)`\
   `print(consume_result['ConsumeJobErrorCode'])`\
   `print(consume_result['ErrorText'])`\
   `new_job = json.loads(consume_result['Job'])`\
   `job_guid = new_job['GUID']`\
   `process_version = json.loads(consume_result['ProcessVersion'])`\
   `python_script_name = process_version['Name'] #Условимся, что имя скрипта робота, который необходимо запустить, передаётся в названии версии процесса`\
   `task = json.loads(consume_result[' Task '])`<br>
3. В случае успешного получения новой Работы из Оркестратора выполнить HTTP PUT запрос к скрипту `/api/job/update` Оркестратора. Передать в параметрах GUID полученной Работы Робота (guid) и новый статус Работы `Status_In_Progress`.\
   \
   Справочник значений статусов Работ:\
   \
   `Status_Created = 0; #Работа создана`\
   `Status_Pending = 1; #Работа ожидает, когда робот возьмет её в работу`\
   `Status_Aborting = 2; #Работа находится в стадии жесткой остановки (прерывания)`\
   `Status_Aborted = 3; #Работа успешно прервана`\
   `Status_Success = 4; #Работа успешно завершена`\
   `Status_Failed = 5; #Работа неуспешно завершена`\
   `Status_Stopping = 6; #Работа находится в стадии остановки мягкой остановки`\
   `Status_Stopped = 7; #Работа успешно остановлена после запроса мягкой остановки`\
   `Status_In_Progress = 8; #Работа в данный момент выполняется`\
   \
   Пример вызова:\
   \
   `import requests`\
   `import base64`\
   `import json`\
   \
   `from requests.packages.urllib3.exceptions import InsecureRequestWarning`\
   `requests.packages.urllib3.disable_warnings(InsecureRequestWarning)`\
   `host = 'http://192.168.1.111:4500' #хост оркестратора`\
   `robot_guid = 'da8bc2f0-8065-4385-b867-405e66b8e151' #GUID робота`\
   \
   `headers = {`\
   `'Authorization': 'Basic ' + base64.b64encode(robot_guid.encode('utf-8')).decode('utf-8')`\
   `}`\
   \
   `job = {`\
   `'guid': job_guid, #GUID текущей работы`\
   `'status': 8 #новый статус работы`\
   `}`\
   \
   `r = requests.put(host + '/api/job/update', data=job, headers=headers, verify=False)`\
   `print(r.text)`<br>
4. Приступить к выполнению Python-скрипта Робота с именем, равным `python_script_name`. По возможности периодически повторять запросы к скрипту `/api/robot/heartbeat` с корректным значением `JobGUID` и `Status = 3 (Status_Working)`.\
   \
   Рекомендуется отправлять этот запрос не чаще раза в 10 секунд. В случае получения в ответ статуса `HeartbeatErrorCode == 10` необходимо немедленно прекратить (прервать) выполнение Python-скрипта Робота.\
   \
   В случае получения в ответ статуса `HeartbeatErrorCode == 20` необходимо выполнить корректное завершение Python-скрипта Робота.
5. После завершения Python-скрипта Робота выполнить HTTP PUT запрос к скрипту `/api/job/update` Оркестратора. Передать в параметрах GUID текущей Работы Робота (guid) и новый статус Работы в зависимости от результата её завершения согласно справочнику, приведенному выше.
6. Затем выполнить HTTP POST запрос к скрипту `/api/robot/heartbeat` Оркестратора со статусом `Status = 2 (Status_Ready)` и перейти к шагу 2 алгоритма фреймворка.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sherparpa.ru/sherpa-rpa/sherpa-orchestrator/python-sherpa-framework/algoritm-raboty-python-freimvorka.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
