Automação de até 6 Sessões SAP GUI
Entendendo o Conceito
A automação do SAP GUI por meio de scripts externos é viabilizada pela interface de Component Object Model (COM) do Windows, acessível em Python através da biblioteca pywin32 [7]. O SAP GUI Scripting permite simular interações humanas diretamente nos elementos da interface de usuário das transações.
Para processar uma fila volumosa de itens, como um lote de 1.000 registros, a execução sequencial em uma única janela pode apresentar lentidão considerável. A utilização de uma fila compartilhada (queue.Queue) para alimentar múltiplas threads paralelas que processam itens sob demanda reduz drasticamente o tempo total de execução e balanceia a carga de trabalho de forma automática [1, 7].
A classe ThreadPoolExecutor, contida no módulo concurrent.futures, simplifica o gerenciamento de threads ao encapsular a criação, inicialização e finalização das threads em um pool sob demanda [7]. Ao definir max_workers=3, o executor garante que exatamente três threads concorrentes sejam mantidas ativas para processar a fila compartilhada. Como o SAP GUI limita o número de sessões simultâneas a até seis por conexão, o script realiza o login inicial com o Usuário X e cria duas novas janelas [2]. As três threads do pool assumem, individualmente, uma das três sessões ativas do SAP GUI (índices 0, 1 e 2), inicializando e liberando as dependências COM de forma isolada dentro de cada thread de execução do pool [7].
Passo a Passo
- Instalar a biblioteca do sistema operacional para gerenciamento COM com o comando
pip install pywin32[3]. - Configurar o ambiente cliente do SAP GUI para habilitar a execução de scripts nas opções de acessibilidade da ferramenta [3].
- Garantir que o parâmetro de sistema
sapgui/user_scriptingesteja ativo com valor verdadeiro no servidor SAP [3]. - Desenvolver o script Python importando os módulos
concurrent.futures,queueewin32com.client[7]. - Inicializar o SAP Logon, realizar o login com o Usuário X e criar duas novas sessões adicionais utilizando o comando
session.CreateSession()[2, 7]. - Instanciar uma fila thread-safe (
queue.Queue()) e preenchê-la com os 1.000 itens de processamento. - Declarar um bloco gerenciador de contexto
with ThreadPoolExecutor(max_workers=3) as executor:para instanciar o pool de threads. - Enviar as três tarefas de processamento de fila ao executor através do método
executor.submit(), mapeando os índices de sessão 0, 1 e 2. - Utilizar o método
queue.join()para suspender a execução da thread principal até que os 1.000 itens tenham sido processados pelas threads do pool [7].
Explicando o código
import queue
import time
import win32com.client
import pythoncom
from concurrent.futures import ThreadPoolExecutor
CONNECTION_NAME = "Conexao_Producao"
USER_X = "USUARIO_X"
PASSWORD_X = "SENHA_X"
LANGUAGE = "PT"
fila_compartilhada = queue.Queue()
for i in range(1, 1001):
fila_compartilhada.put(f"Item_{i}")
def processar_fila_sap(session_index):
pythoncom.CoInitialize()
try:
sap_gui = win32com.client.GetObject("SAPGUI")
application = sap_gui.GetScriptingEngine
connection = application.Connections(0)
session = connection.Sessions(session_index)
while True:
try:
item = fila_compartilhada.get_nowait()
except queue.Empty:
break
try:
session.findById("wnd[0]/usr/txtRSYST-BNAME").text = item
session.findById("wnd[0]").sendVKey(0)
time.sleep(0.1)
except Exception as e:
print(f"Erro ao processar item {item} na sessao {session_index}: {str(e)}")
finally:
fila_compartilhada.task_done()
except Exception as e:
print(f"Erro critico na thread da sessao {session_index}: {str(e)}")
finally:
pythoncom.CoUninitialize()
def main():
sap_gui = win32com.client.GetObject("SAPGUI")
application = sap_gui.GetScriptingEngine
connection = application.OpenConnection(CONNECTION_NAME, True)
session = connection.Sessions(0)
session.findById("wnd[0]/usr/txtRSYST-BNAME").text = USER_X
session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = PASSWORD_X
session.findById("wnd[0]/usr/txtRSYST-LANGU").text = LANGUAGE
session.findById("wnd[0]").sendVKey(0)
session.CreateSession()
session.CreateSession()
time.sleep(3)
with ThreadPoolExecutor(max_workers=3) as executor:
for i in range(3):
executor.submit(processar_fila_sap, i)
fila_compartilhada.join()
if __name__ == "__main__":
main()
ThreadPoolExecutor(max_workers=3) as executor: Instancia um pool de threads gerenciado que limita a concorrência a no máximo três threads ativas simultaneamente e garante a destruição e liberação correta de recursos ao sair do blocowith[7].executor.submit(processar_fila_sap, i): Agenda a execução da funçãoprocessar_fila_sapde forma assíncrona no pool, passando o valor deicorrespondente ao índice da sessão do SAP.queue.Queue(): Cria uma instância de fila compartilhada segura para acesso concorrente, gerenciando travas internas de sincronização de dados de forma automática [7].fila_compartilhada.get_nowait(): Recupera um item da fila de forma síncrona sem bloquear a thread. Dispara a exceçãoqueue.Emptycaso não existam mais itens.fila_compartilhada.task_done(): Envia um sinal para a fila indicando que o processamento do item recuperado anteriormente foi totalmente finalizado [7].fila_compartilhada.join(): Bloqueia a execução do fluxo principal até que o número de chamadas detask_done()se iguale ao número de itens inseridos na fila.pythoncom.CoInitialize(): Registra e inicializa o interpretador COM do Windows na thread corrente do Python, permitindo que cada thread controle sua respectiva janela do SAP GUI de forma isolada [7].session.CreateSession(): Envia um comando para a conexão ativa criar uma nova janela de sessão idêntica sob as mesmas credenciais do Usuário X [2].
Observações
- Ciclo de Vida do COM: Mesmo gerenciadas por um pool estruturado como o
ThreadPoolExecutor, cada thread criada em segundo plano representa um ambiente COM novo. O uso depythoncom.CoInitialize()epythoncom.CoUninitialize()continua estritamente obrigatório [7]. - Sincronia do Pool: O método
fila_compartilhada.join()deve ser invocado antes do término do bloco gerenciador de contextowith ThreadPoolExecutor, garantindo que o pool não inicie o processo de encerramento das threads antes que todos os itens tenham sido despachados. - Configuração de Sessões Mínimas: É necessário que a quantidade de sessões do SAP criadas via
CreateSession()corresponda exatamente ao parâmetromax_workersdefinido no pool. Se existirem menos sessões que workers ativos, threads tentarão acessar índices de sessões inexistentes, ocasionando erros de automação. - Evitando Deadlocks na Fila: O método de consumo
get_nowait()deve ser protegido por bloco try-except tratando a exceçãoqueue.Emptypara permitir que as threads encerrem sua execução naturalmente quando o trabalho acabar. - Bloqueio de Tabelas: O processamento simultâneo na mesma transação SAP pode gerar erros de bloqueio de tabelas no banco de dados. Os dados colocados na fila compartilhada devem ser transacionalmente independentes.
Referências
- SAP Community. How to Execute SAP GUI Scripting Parallel. Disponível em: https://community.sap.com/t5/technology-blog-posts-by-members/how-to-execute-sap-gui-scripting-parallel/ba-p/13509718.
- SAP Help Portal. SAP GUI - Working with Multiple Sessions. Disponível em: https://help.sap.com/docs/SAP_NETWEAVER_740/b1c834a22d05483b8a75710743b5ff26/9c7810c251d345aabe5a01845372ac14.html.
- Stack Overflow. Multiprocessing in SAP GUI using Python. Disponível em: https://stackoverflow.com/questions/72533754/multiprocessing-in-sap-gui-using-python.