Faz bastante tempo desde a última vez que escrevi uma postagem de atualização do IoP.
Então, o que há de novo desde o lançamento da interface de linha de comando IoP?
Dois novos grandes recursos foram adicionados ao IoP:
- Rebranding: o módulo
grongier.pex
foi renomeado paraiop
para refletir o novo nome do projeto. - suporte Async: IoP agora suporta funções assíncronas e co-rotinas.
Rebranding
O módulo grongier.pex
foi renomeado para iop
para refletir o novo nome do projeto.
O módulo grongier.pex
ainda está disponível para compatibilidade retroativa, mas será removido no futuro.
suporte Async
O IoP suporta chamadas assíncronas há um bom tempo, mas não era possível usar funções e co-rotinas assíncronas diretamente nele.
Antes de pular dentro desse novo recurso, vou explicar como chamadas assíncronas funcionam no InterSystems IRIS e apresentar dois exemplos de como usar chamadas assíncronas IoP.
Chamadas async legado
Vamos ver como chamadas async legado funcionam:
from iop import BusinessProcess
from msg import MyMessage
class MyBP(BusinessProcess):
def on_message(self, request):
msg_one = MyMessage(message="Message1")
msg_two = MyMessage(message="Message2")
self.send_request_async("Python.MyBO", msg_one,completion_key="1")
self.send_request_async("Python.MyBO", msg_two,completion_key="2")
def on_response(self, request, response, call_request, call_response, completion_key):
if completion_key == "1":
self.response_one = call_response
elif completion_key == "2":
self.response_two = call_response
def on_complete(self, request, response):
self.log_info(f"Received response one: {self.response_one.message}")
self.log_info(f"Received response two: {self.response_two.message}")
Basicamente elas funcionam da mesma maneira que chamadas async funcionam em IRIS. O método send_request_async
envia uma requisição ao Business Operation e o método on_response
é chamado quando a resposta é recebida.
Você pode distinguir as respostas pelo parâmetro completion_key
Enviar múltiplas requisições síncronas
Não é exatamente um novo recurso, mas vale a pena mencionar que você pode mandar múltiplas requisições síncronas em paralelo:
from iop import BusinessProcess
from msg import MyMessage
class MyMultiBP(BusinessProcess):
def on_message(self, request):
msg_one = MyMessage(message="Message1")
msg_two = MyMessage(message="Message2")
tuple_responses = self.send_multi_request_sync([("Python.MyMultiBO", msg_one),
("Python.MyMultiBO", msg_two)])
self.log_info("All requests have been processed")
for target,request,response,status in tuple_responses:
self.log_info(f"Received response: {response.message}")
Aqui estamos mandando duas requisições ao mesmo Business Operation em paralelo.
A resposta é uma tupla com o objetivo, requisição, resposta e status de cada chamada.
É bastante útil quando você precisa enviar múltiplas requisições e não se importa com a ordem das respostas.
Funções Async e co-rotinas
Agora vamos ver como usar funções assíncronas e co-rotinas no IoP:
import asyncio
from iop import BusinessProcess
from msg import MyMessage
class MyAsyncNGBP(BusinessProcess):
def on_message(self, request):
results = asyncio.run(self.await_response(request))
for result in results:
print(f"Received response: {result.message}")
async def await_response(self, request):
msg_one = MyMessage(message="Message1")
msg_two = MyMessage(message="Message2")
# use asyncio.gather to send multiple requests asynchronously
# using the send_request_async_ng method
tasks = [self.send_request_async_ng("Python.MyAsyncNGBO", msg_one),
self.send_request_async_ng("Python.MyAsyncNGBO", msg_two)]
return await asyncio.gather(*tasks)
Neste exemplo, estamos enviando múltiplas requisições para o mesmo Business Operation em paralelo usando o método send_request_async_ng
.
Se você leu esse post cuidadosamente até este ponto, por favor comente "Boomerang". Isso pode ser um detalhe para você, mas para mim significa muito. Obrigado!
O método await_response
é uma co-rotina que envia múltiplas requisições e espera por todas as respostas.
Graças a função
asyncio.gather`, podemos esperar por todas as respostas serem recebidas em paralelo
Os benefícios das funções e co-rotinas assíncronas são:
- Melhor performance: você pode enviar múltiplas requisições em paralelo.
- Mais fácil de ler e manter: você pode usar a palavra chave
await
para esperar por respostas. - Maior flexibilidade: você pode usar o módulo
asyncio
para criar fluxos de trabalho complexos - Mais controle: você pode usar o módulo
asyncio
para lidar com exceções e timeouts.
Conclusão
Quais são as diferenças entre send_request_async
, send_multi_request_sync
e send_request_async_ng
?
send_request_async
: envia uma requisição ao Business Operation e espera a resposta se o métodoon_response
for implementado e o parâmetrocompletion_key
usado- benefício: você pode usar chamadas assíncronas da maneira que está acostumado.
- desvantagem: pode ser difícil de manter se você precisa enviar múltiplas requisições em paralelo.
send_multi_request_sync
: envia múltiplas requisições ao mesmo Business Operation em paralelo e espera por todas as respostas para serem recebidas.- benefício: fácil de usar.
- desvantagem: você pode controlar a ordem das respostas (quero dizer se a lista de respostas não for ordenada)
send_request_async_ng
: envia múltiplas requisições ao mesmo Business Operation em paralelo e espera por todas as respostas.- benefício: você pode controlar a ordem das respostas
- desvantagem: você precisa usar funções e co-rotinas assíncronas.
Feliz multithreading!