# Algoritmo de funcionamento do framework Python

O script do framework Python, executado pelo Agendador do Windows, deve seguir o seguinte algoritmo:

1. Realizar uma requisição HTTP POST para o script `/api/robot/heartbeat` do Orquestrador. Passar nos parâmetros:
   1. GUID deste Robô (RobotGUID),
   2. nome do computador (Machine),
   3. endereço IP da máquina (IP),
   4. endereço MAC da máquina (MAC),
   5. status atual do Robô (Status),
   6. GUID do Trabalho que está sendo executado no momento (JobGUID),
   7. nome do Trabalho que está sendo executado no momento (JobName),
   8. tipo de Trabalho (JobType, sempre deve ter o tipo Orchestrated, valor 1).

Os dados de saída (no formato JSON):

* HeartbeatErrorCode,
* ErrorText,
* HasNewJob.

O script pode retornar outros parâmetros na resposta que não são utilizados no contexto da Tarefa atual.

Dicionário de status dos Robôs:

```
Status_Disconnected = 0; # robô desconectado
Status_Unlicensed     = 1; # robô não licenciado
Status_Ready        = 2; # robô não está executando trabalhos e está pronto para receber novos trabalhos
Status_Working    = 3; # robô está executando o trabalho atual
```

Dicionário de valores ErrorCode:

```
HeartbeatErrorCode_NoError = 0;  # sem erros
HeartbeatErrorCode_RobotNotFound = 101;  # robô com o GUID especificado não encontrado
HeartbeatErrorCode_JobAborting = 10;   # orquestrador solicitou a parada forçada deste script (Abort)
HeartbeatErrorCode_JobStopping = 20;   # orquestrador solicitou a parada suave deste script (Stop)
```

Dicionário de valores HasNewJob:

```
HasNewJob_NoJob = 0 # para este robô não há novos trabalhos
HasNewJob_JobFound = 1 # para este robô há novos trabalhos que precisam ser obtidos com a chamada ConsumeNextJob
```

Na primeira execução do script, deve-se passar o valor `Status = 2` (Status\_Ready). Também na primeira execução, quando o nome e o GUID do trabalho em execução ainda são desconhecidos, esses campos podem permanecer vazios.

Exemplo de chamada:

```
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' #host do orquestrador
robot_guid = 'da8bc2f0-8065-4385-b867-405e66b8e151' #GUID do robô
headers = {
    'Authorization': 'Basic ' + base64.b64encode(robot_guid.encode('utf-8')).decode('utf-8')
}
req = {
    'RobotGUID': robot_guid,   #GUID do robô
    'Machine': robot_machine,   #Nome da máquina
    'IP': robot_ip,   #Endereço IP do robô
    'MAC': robot_mac,   #Endereço MAC do robô
    'Status': 2,   #status do robô
    'JobGUID': '',  #GUID do trabalho
    'JobName': '',   #nome do script em execução, ou seja, python_script_name adiante no texto
    'JobType': 1   #tipo de trabalho, sempre valor 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. Caso a resposta seja `HasNewJob == 0`, encerrar a execução do script do framework e sair da conta do Windows usando Log off.\
   \
   Caso a resposta seja `HasNewJob == 1`, realizar uma requisição HTTP POST para o script `/api/robot/consumeNextJob` do Orquestrador.\
   \
   Dados de entrada:

   1. GUID do Robô (RobotGUID),
   2. status atual do Robô (Status).

   \
   Dados de saída (no formato JSON):

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

   Dicionário de valores ConsumeJobErrorCode:\
   \
   `ConsumeJobErrorCode = 0; # sem erros`\
   `ConsumeJobErrorCode = 101; # robô com o GUID especificado não encontrado`\
   `ConsumeJobErrorCode = 102; # novo trabalho não encontrado`\
   \
   Exemplo de chamada:\
   \
   `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' #host do orquestrador`\
   `robot_guid = 'da8bc2f0-8065-4385-b867-405e66b8e151' #GUID do robô`\
   \
   `headers = {`\
   `'Authorization': 'Basic ' + base64.b64encode(robot_guid.encode('utf-8')).decode('utf-8')`\
   `}`\
   \
   `cnj = {`\
   `'RobotGUID': robot_guid #GUID do robô`\
   `}`\
   \
   `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'] #Convenhamos que o nome do script do robô que deve ser executado é passado no nome da versão do processo`\
   `task = json.loads(consume_result[' Task '])`<br>
3. Em caso de sucesso na obtenção de um novo Trabalho do Orquestrador, realizar uma requisição HTTP PUT para o script `/api/job/update` do Orquestrador. Passar nos parâmetros o GUID do Trabalho obtido (guid) e o novo status do Trabalho `Status_In_Progress`.\
   \
   Dicionário de valores dos status dos Trabalhos:\
   \
   `Status_Created = 0; #Trabalho criado`\
   `Status_Pending = 1; #Trabalho aguardando que o robô o pegue para execução`\
   `Status_Aborting = 2; #Trabalho em fase de parada forçada (interrupção)`\
   `Status_Aborted = 3; #Trabalho interrompido com sucesso`\
   `Status_Success = 4; #Trabalho concluído com sucesso`\
   `Status_Failed = 5; #Trabalho não concluído com sucesso`\
   `Status_Stopping = 6; #Trabalho em fase de parada suave`\
   `Status_Stopped = 7; #Trabalho parado com sucesso após solicitação de parada suave`\
   `Status_In_Progress = 8; #Trabalho está sendo executado no momento`\
   \
   Exemplo de chamada:\
   \
   `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' #host do orquestrador`\
   `robot_guid = 'da8bc2f0-8065-4385-b867-405e66b8e151' #GUID do robô`\
   \
   `headers = {`\
   `'Authorization': 'Basic ' + base64.b64encode(robot_guid.encode('utf-8')).decode('utf-8')`\
   `}`\
   \
   `job = {`\
   `'guid': job_guid, #GUID do trabalho atual`\
   `'status': 8 #novo status do trabalho`\
   `}`\
   \
   `r = requests.put(host + '/api/job/update', data=job, headers=headers, verify=False)`\
   `print(r.text)`<br>
4. Iniciar a execução do script Python do Robô com o nome igual a `python_script_name`. Sempre que possível, repetir periodicamente as requisições para o script `/api/robot/heartbeat` com o valor correto de `JobGUID` e `Status = 3 (Status_Working)`.\
   \
   Recomenda-se enviar essa requisição não mais do que uma vez a cada 10 segundos. Caso a resposta retorne o status `HeartbeatErrorCode == 10`, é necessário interromper imediatamente a execução do script Python do Robô.\
   \
   Caso a resposta retorne o status `HeartbeatErrorCode == 20`, é necessário realizar o encerramento correto do script Python do Robô.
5. Após a conclusão do script Python do Robô, realizar uma requisição HTTP PUT para o script `/api/job/update` do Orquestrador. Passar nos parâmetros o GUID do Trabalho atual do Robô (guid) e o novo status do Trabalho dependendo do resultado de sua conclusão, conforme o dicionário apresentado acima.
6. Em seguida, realizar uma requisição HTTP POST para o script `/api/robot/heartbeat` do Orquestrador com o status `Status = 2 (Status_Ready)` e retornar ao passo 2 do algoritmo do framework.


---

# 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/pt/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.
