Avvio di uno script Python da un trigger di inserimento


10

Abbiamo un bel pezzo di pitone che invia alcune e-mail e interagisce con un sistema cloud. Funziona bene. Ma dobbiamo attivarlo ogni pochi minuti per eseguire il polling del db. Abbiamo davvero bisogno, per motivi di lavoro, di attivare lo script Python in tempo reale, quindi non c'è alcun ritardo di polling. (Questo serve ai venditori che sono al telefono con i clienti.)

Non vogliamo davvero un ciclo di polling di 1 minuto. O 30 secondi. Vogliamo che il disco venga mostrato nel db e che le cose accadano immediatamente.

Il modo più veloce per fare questo volo è farlo sparare quando un tipo di record specifico viene inserito in una tabella.

Possiamo sparare uno script Python da un trigger?

Secondo la nota di Aaron di seguito, sappiamo che si tratta di una cosa molto brutta ™ , ma questa tabella ha pochissimo utilizzo (0-12 inserti al giorno). Il polling della tabella non riesce a soddisfare le nostre esigenze aziendali (abbiamo bisogno che il .py venga eseguito immediatamente - fa molto di più che inviare un'e-mail).

Riteniamo che un modo per soddisfare le nostre esigenze aziendali sia impostare la versione .net di python su SQL Server, quindi fare in modo che T-SQL chiami lo script python nel modo in cui chiama roba C # ... ma non abbiamo idea di come effettivamente farlo! (ergo questa domanda).

Docs / dettagli?


Ho posto una domanda di follow-up su Stack Overflow: come posso creare una procedura CLR Python in SQL Server?


La domanda sotto la domanda : hai un pezzo di pitone. Vuoi che si attivi da un trigger SQL, ma sai che è una cosa molto brutta. Quindi cosa fai per ottenere lo stesso effetto senza avere il codice Python nel mezzo di un'operazione SQL?

Qual è l'approccio non trigger e non polling per risolvere questa esigenza?

(Lo stesso effetto = "inserisce / aggiorna / elimina si verifica in una tabella e uno script python viene attivato entro 2 secondi dall'evento db, senza eseguire il polling della tabella")


Stai cambiando la domanda cinque anni dopo? Pieno di conflitti. Il polling della tabella non soddisfa le esigenze della tua azienda perché il programma deve essere eseguito immediatamente, ma nell'aggiornamento dici che un ritardo di 2 secondi è accettabile? Confondere. Se un ritardo di 2 secondi è accettabile, penso che lo sia anche il polling della tabella.
Aaron Bertrand

1
@AaronBertrand Concordo sul fatto che questa domanda non è conforme alla visione di tutti della realtà. Ma se ci prendiamo un momento, e supponiamo che l'interrogatore sia intelligente e sincero nel suo bisogno di una ricerca non-attiva-ma-agisce come un grilletto, anche noi (come comunità SE) possiamo aiutare a trovare un modo fwd (o respinge la domanda, che in realtà non fa sparire la necessità / il problema). FWIW.
Jonesome ripristina Monica il

Va bene, ma devi scegliere quale problema risolvere e quindi risolvere la domanda (o forse iniziare una nuova se la risposta che hai ricevuto 5 anni fa era accettabile, ma oggi non è più accettabile, sia perché i tuoi requisiti sono cambiati da allora ). Attualmente dici che non vuoi il polling o un trigger e dici anche che deve essere immediato e un ritardo di 2 secondi va bene.
Aaron Bertrand

Ora, questo è uno scenario, in cui NoSQL non arriva a portata di mano a differenza di DBMS, perché DBMS in grado di gestire i trigger e contribuire come un livello di applicazione (più di una memorizzazione dei dati)
overexchange

@samsmith Hai passato questa risposta?
Scambio eccessivo del

Risposte:


12

Non fare in modo che la transazione dell'utente attenda il completamento (si spera!) Corretto dello script Python. Tutta la tua transazione si trova lì e attende che questo processo esterno venga eseguito, prova a inviare e-mail, ecc. Dubito che l'e-mail debba davvero uscire in quell'istante, soprattutto dato che non puoi controllare i ritardi che ha mentre viene instradato nella posta in arrivo del destinatario comunque. Perché non eseguire il processo più frequentemente, se il tempismo è così importante?

Dai un'occhiata a questo suggerimento .

Se davvero, davvero, vuoi davvero farlo nel modo sbagliato, puoi semplicemente abilitare xp_cmdshelle sparare.

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

Ora, supponendo che l'utente abbia accesso xp_cmdshelle / o l'account del servizio SQL Server possa vedere la cartella in cui è archiviato lo script python, dovresti essere in grado di farlo dal tuo trigger:

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

A parte questo, dovresti dichiarare nella tua domanda che sei consapevole che questa è una brutta cosa TM , ma non ti preoccupi di ciò, per qualsiasi motivo. Continuo a non pensare che otterrai il tempo reale come ti aspetti, anche se lo fai dal grilletto. Hai preso in considerazione la posta del database invece di Python?


Aaron, tutti i tuoi punti sono validi, ma questo è il mio problema. Voglio sparare Python da un trigger e non ho problemi con i problemi. (Posso fare in modo che il trigger sulla tabella reale inserisca un valore in una tabella "job" e un trigger sulla tabella "job" esegua python ...)
Jonesome Reinstate Monica

4
Inoltre, il tuo trigger -> altra tabella -> altra idea di trigger soffre ancora dello stesso problema, solo ora è peggio. La transazione originale deve ancora attendere il completamento di tutta l'attività a cascata.
Aaron Bertrand

buona chiamata RE a cascata il problema. Non ci andremo!
Jonesome ripristina Monica il

OP potenziato, per riformulare la domanda
Jonesome ripristina Monica il

2

"inserire / aggiornare / cancellare avviene in una tabella e uno script python viene attivato entro 2 secondi dall'evento db,

Prima di tutto, se si utilizza un trigger per scrivere un messaggio in una tabella dedicata a questo scopo, è possibile eseguire continuamente il processo di pooling con un'attesa di 1 secondo o anche meno. La chiave è rendere la query di polling abbastanza economica (<1ms) e non interferire con qualsiasi altra transazione (quindi la "tabella delle code" dedicata).

Ad esempio, fai eseguire al tuo processo di polling un batch come questo:

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.*

Attendere fino a 25 secondi affinché appaia una riga nella tabella, eseguendo il polling ogni secondo. Al timeout restituisce semplicemente un set di risultati vuoto.

senza eseguire il polling del tavolo

La cosa più semplice è quindi utilizzare Service Broker, insieme a una procedura di attivazione interna che richiama Python tramite xp_cmdshell, o un processo esterno che esegue un ciclo RECEIVE di blocco sulla coda del broker del servizio di destinazione. Ecco come funziona Database Mail sotto il cofano.



2

Per ridurre al minimo l'impatto dell'esecuzione dello script Python in modo sincrono dal trigger, è possibile racchiudere il codice Python in un 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()

È quindi possibile inviare una richiesta HTTP dal trigger al demone sopra, come mostrato ad esempio in queste domande e risposte . Il gestore di richieste può anche generare un thread separato per eseguire la logica di Python in modo asincrono.


Bella risposta!!! La maggior parte delle applicazioni di mons. Della metà degli anni '90 (su cui ho lavorato) eseguiva il polling del database, con un intervallo di polling.
Scambiare il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.