Iniciando um script python a partir de um gatilho de inserção

10

Temos um belo pedaço de python que envia alguns emails e interage com um sistema em nuvem. Funciona bem. Mas temos que acioná-lo a cada poucos minutos para pesquisar o banco de dados. Nós realmente precisamos, para fins comerciais, que o script python seja acionado em tempo real, para que não haja atraso na pesquisa. (Isso atende as pessoas de vendas que estão ao telefone com os clientes.)

Realmente não queremos um loop de pesquisa de 1 minuto. Ou 30 segundos. Queremos que o registro seja exibido no banco de dados e que as coisas aconteçam imediatamente.

A maneira mais rápida de fazer essa mosca ser acionada quando um tipo de registro específico é inserido em uma tabela.

Podemos disparar um script python a partir de um gatilho?

De acordo com a nota de Aaron abaixo, sabemos que essa é uma coisa muito ruim ™ , mas essa tabela tem muito pouco uso (0 a 12 inserções por dia). A pesquisa da tabela não atende às nossas necessidades comerciais (precisamos que o .py seja executado imediatamente - ele faz muito mais do que enviar um email).

Acreditamos que uma maneira de atender às nossas necessidades comerciais é configurar a versão .net do python no SQL Server e, em seguida, fazer com que o T-SQL chame o script python da maneira que chama as coisas de C # ... mas não temos idéia de como realmente faça isso! (ergo esta pergunta).

Documentos / detalhes?


Fiz uma pergunta de acompanhamento no estouro de pilha: como criar um procedimento Python CLR no SQL Server?


A questão sob a pergunta : você tem um pedaço de python. Você deseja que ele seja acionado a partir de um gatilho SQL, mas sabe que isso é muito ruim. Então, o que você faz para realmente obter o mesmo efeito sem ter código python no meio de uma operação SQL?

Qual é a abordagem não acionadora e não sondadora para resolver essa necessidade?

(O mesmo efeito = "inserir / atualizar / excluir acontece em uma tabela e um script python é acionado dentro de 2 segundos do evento db, sem consultar a tabela")

Jonesome Restabelecer Monica
fonte
Você está mudando a questão cinco anos depois? Cheio de conflitos. A pesquisa da tabela não atende às suas necessidades de negócios porque o py precisa ser executado imediatamente, mas na atualização você diz que um atraso de 2 segundos é aceitável? Confuso. Se um atraso de 2 segundos for aceitável, acho que sim, está pesquisando a tabela.
Aaron Bertrand
11
@AaronBertrand Concordo que esta questão não está de acordo com a visão de todos da realidade. Mas, se tomarmos um momento e presumirmos que o interlocutor é inteligente e sincero em sua necessidade de uma missão que não é real, mas que age como um gatilho, nós (como uma comunidade do SE) podemos ajudar a encontrar uma maneira fwd (ou ignore a pergunta, que na verdade não faz a necessidade / problema desaparecer). fwiw.
Jonesome Reinstate Monica
Tudo bem, mas você precisa escolher qual problema resolver e, em seguida, corrigir a questão (ou talvez iniciar um novo se a resposta que você obteve 5 anos atrás era aceitável, mas hoje não é mais aceitável hoje, seja porque seus requisitos mudaram desde então ) Atualmente, você diz que não deseja uma pesquisa ou um gatilho e também diz que deve ser imediato e que um atraso de 2 segundos é bom.
Aaron Bertrand
Agora, este é um cenário em que o NoSQL não é útil ao contrário do DBMS, porque o DBMS pode gerenciar gatilhos e contribuir como uma camada de aplicativo (mais do que um armazenamento de dados)
superexclua
@samsmith Você passou por esta resposta?
overexchange 6/01/19

Respostas:

12

Não faça sua transação de usuário aguardar a (com sorte!) Conclusão bem-sucedida do script Python. Toda a sua transação fica lá e aguarda a execução desse processo externo, tente enviar e-mails etc. Duvido que o e-mail realmente tenha que sair naquele instante - especialmente porque você não pode controlar os atrasos que tem ao ser roteado de qualquer maneira para a caixa de entrada do destinatário. Por que não apenas executar o processo com mais frequência, se o tempo é tão importante?

Por favor, dê uma olhada nesta dica .

Se você realmente, realmente, realmente deseja fazer isso da maneira errada, basta ativar xp_cmdshelle disparar.

EXEC sp_configure 'show advanced options', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO
EXEC sp_configure 'xp_cmdshell', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO

Agora, supondo que o usuário tenha acesso xp_cmdshelle / ou a conta de serviço do SQL Server possa ver a pasta em que o script python está armazenado, você poderá fazer isso de dentro do seu gatilho:

EXEC master..xp_cmdshell N'C:\Python27\python.exe C:\source\NotifyAgents.py';

Como um aparte, você deve declarar na sua pergunta que está ciente de que isso é uma coisa muito ruim da MT , mas não está preocupado com isso, por qualquer motivo. Ainda acho que você não terá o tempo real que espera, mesmo se disparar isso do gatilho. Você considerou o correio do banco de dados em vez do python?

Aaron Bertrand
fonte
Aaron, todos os seus pontos são válidos, mas esse é o meu problema. Quero disparar python a partir de um gatilho e não tenho problemas com os problemas. (Posso fazer com que o gatilho na tabela real insira um valor em uma tabela "job" e um gatilho na tabela "job" execute python ...) #
Jonesome Reinstate Monica 13/13/13
4
Além disso, sua ideia de gatilho -> outra tabela -> outra gatilho ainda sofre do mesmo problema, só que agora é pior. A transação original ainda precisa aguardar a conclusão de toda essa atividade em cascata.
Aaron Bertrand
boa chamada RE em cascata o problema. Não vai lá!
Jonesome Reinstate Monica
OP aprimorado, para reformular a questão #
Jonesome Reinstate Monica
2

"inserir / atualizar / excluir acontece em uma tabela e um script python é acionado dentro de 2 segundos após o evento db,

Primeiro, se você usar um gatilho para escrever uma mensagem em uma tabela dedicada para esse fim, poderá executar continuamente o processo de pool com uma espera de 1 segundo ou até menos. A chave é tornar a consulta de pesquisa barata o suficiente (<1ms) e não interferir em nenhuma outra transação (portanto, a "tabela de fila" dedicada).

Por exemplo, seu processo de votação executa um lote como este:

declare @TriesRemaining int = 25
while not exists (select * from queue_table)
begin
  if @TriesRemaining <= 0
    break;
  set @TriesRemaining -= 1
  waitfor delay '0:0:1'
end
delete top (1)  
from queue_table
output deleted.*

Para esperar até 25 segundos para que uma linha apareça na tabela, sondando a cada segundo. Com o tempo limite, ele simplesmente retorna um conjunto de resultados vazio.

sem consultar a tabela

A coisa mais simples, então, é usar o Service Broker, juntamente com um Procedimento de Ativação Interna que chama o Python através de xp_cmdshell, ou um processo externo que faz um loop em um RECEIVE bloqueador na fila do broker de serviço de destino. É assim que o Database Mail funciona oculto.

David Browne - Microsoft
fonte
Há um bom artigo detalhado sobre a configuração do service broker .
mustaccio
2

Para minimizar o impacto da execução do script Python de forma síncrona a partir do seu gatilho, você pode agrupar seu código Python em BaseHTTPServer:

import BaseHTTPServer

class MyHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_POST(self):
        print "Serving %s" % self.path
        # Your code here
        self.send_response(200, "OK")

def run(server_class=BaseHTTPServer.HTTPServer,
        handler_class=MyHTTPHandler):
    server_address = ('', 8000)
    httpd = server_class(server_address, handler_class)
    httpd.serve_forever()

if __name__ == "__main__":
    run()

Em seguida, você pode enviar uma solicitação HTTP do seu gatilho para o daemon acima, conforme mostrado, por exemplo, nesta SO Q&A . O manipulador de solicitações pode gerar um thread separado para executar sua lógica Python de forma assíncrona.

mustaccio
fonte
Boa resposta!!! A maioria dos aplicativos de mgr de meados dos anos 90 (que trabalhei) pesquisava o banco de dados, com um intervalo de pesquisa.
overexchange 6/01/19