Lancement d'un script python à partir d'un déclencheur d'insertion

10

Nous avons un joli morceau de python qui envoie des e-mails et interagit avec un système cloud. Fonctionne bien. Mais nous devons le tirer toutes les quelques minutes pour interroger la base de données. Nous avons vraiment besoin, à des fins commerciales, que le script python se déclenche en temps réel, donc il n'y a pas de délai d'interrogation. (Cela sert les vendeurs qui sont au téléphone avec les clients.)

Nous ne voulons vraiment pas d'une boucle d'interrogation d'une minute. Ou 30 secondes. Nous voulons que le disque s'affiche dans la base de données et que les choses se produisent immédiatement.

Le moyen le plus rapide de faire voler cette mouche est de la déclencher lorsqu'un type d'enregistrement spécifique est inséré dans une table.

Pouvons-nous lancer un script python à partir d'un déclencheur?

Selon la note d'Aaron ci-dessous, nous savons que c'est une Very Bad Thing ™ , mais ce tableau est très très peu utilisé (0-12 inserts par jour). Interroger la table ne répond pas à nos besoins commerciaux (nous avons besoin que le .py s'exécute immédiatement - il fait bien plus que d'envoyer un e-mail).

Nous pensons qu'un moyen de répondre à nos besoins commerciaux est de configurer la version .net de python sur SQL Server, puis de demander à T-SQL d'appeler le script python de la même façon qu'il appelle les éléments C # ... mais nous ne savons pas comment faites ça! (ergo cette question).

Documents / détails?


J'ai posé une question de suivi sur Stack Overflow: comment créer une procédure Python CLR dans SQL Server?


La question sous la question : vous avez un morceau de python. Vous voulez qu'il se déclenche à partir d'un déclencheur SQL, mais vous savez que c'est une très mauvaise chose. Alors, que faites-vous pour obtenir le même effet sans avoir de code python au milieu d'une opération SQL?

Quelle est l'approche sans déclencheur et sans interrogation pour résoudre ce besoin?

(Le même effet = "insérer / mettre à jour / supprimer se produit dans une table et un script python est déclenché dans les 2 secondes suivant l'événement db, sans interroger la table")

Jonesome réintègre Monica
la source
Vous changez la question cinq ans plus tard? Plein de conflits. L'interrogation de la table ne répond pas aux besoins de votre entreprise car le py doit s'exécuter immédiatement, mais dans la mise à jour, vous dites qu'un délai de 2 secondes est acceptable? Déroutant. Si un délai de 2 secondes est acceptable, je pense qu'il en va de même pour la table.
Aaron Bertrand
1
@AaronBertrand Je suis d'accord que cette question n'est pas conforme à la vision de tout le monde de la réalité. Mais si nous prenons un moment et supposons que le questionneur est intelligent et sincère dans son besoin d'une quête non réelle, mais agit comme une gâchette, nous (en tant que communauté SE) pouvons aider à trouver un moyen fwd (ou ignorer la question, ce qui ne fait pas disparaître le besoin / problème). fwiw.
Jonesome Reinstate Monica
C'est bien, mais vous devez choisir le problème à résoudre, puis résoudre la question (ou peut-être en créer un nouveau si la réponse que vous avez obtenue il y a 5 ans était acceptable, mais n'est plus acceptable aujourd'hui, que ce soit parce que vos besoins ont depuis changé). ). Actuellement, vous dites que vous ne voulez pas d'interrogation ou de déclencheur, et vous dites également qu'il doit être immédiat et qu'un délai de 2 secondes est très bien.
Aaron Bertrand
Maintenant, c'est un scénario où NoSQL n'est pas pratique contrairement au SGBD, car le SGBD peut gérer les déclencheurs et contribuer en tant que couche d'application (plus qu'un stockage de données)
overexchange
@samsmith Avez-vous parcouru cette réponse?
surexchange

Réponses:

12

Ne faites pas attendre votre transaction utilisateur pour la réussite (espérons-le!) Du script Python. Votre transaction entière se trouve là et attend que ce processus externe s'exécute, essaie d'envoyer du courrier, etc. Je doute que l'e-mail doive vraiment sortir à cet instant - d'autant plus que vous ne pouvez pas contrôler les retards qu'il a lorsqu'il est routé dans la boîte de réception du destinataire de toute façon. Pourquoi ne pas simplement exécuter le processus plus fréquemment, si le timing est si important?

Veuillez consulter cette astuce .

Si vous voulez vraiment, vraiment, vraiment faire cela dans le mauvais sens, vous pouvez simplement activer xp_cmdshellet déclencher.

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

Maintenant, en supposant que l'utilisateur a accès xp_cmdshellet / ou que le compte de service SQL Server puisse voir le dossier où le script python est stocké, vous devriez pouvoir le faire à partir de votre déclencheur:

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

Soit dit en passant, vous devez déclarer dans votre question que vous savez que c'est une très mauvaise chose TM , mais vous n'êtes pas concerné par cela, pour quelque raison que ce soit. Je ne pense toujours pas que vous obtiendrez le temps réel que vous attendez, même si vous déclenchez cela depuis la gâchette. Avez-vous pensé au courrier de base de données au lieu de python?

Aaron Bertrand
la source
Aaron, Tous vos points sont valables, mais c'est mon problème. Je veux déclencher python à partir d'un déclencheur, et je n'ai aucun problème avec les problèmes. (Je peux avoir le déclencheur sur la table réelle pousser une valeur dans une table "job", et un déclencheur sur la table "job" exécuter python ...)
Jonesome Reinstate Monica
4
De plus, votre déclencheur -> autre table -> autre idée de déclencheur souffre toujours du même problème, mais maintenant c'est pire. La transaction d'origine doit encore attendre la fin de toute cette activité en cascade.
Aaron Bertrand
bon appel RE en cascade le problème. N'y irai pas!
Jonesome Reinstate Monica
OP amélioré, pour recadrer la question
Jonesome Reinstate Monica
2

"insérer / mettre à jour / supprimer se produit dans une table et un script python est déclenché dans les 2 secondes suivant l'événement db,

Tout d'abord, si vous utilisez un déclencheur pour écrire un message dans une table dédiée à cet effet, vous pouvez exécuter en continu le processus de regroupement avec une attente de 1 seconde, voire moins. L'essentiel est de rendre la requête d'interrogation suffisamment bon marché (<1 ms), et de ne pas interférer avec toute autre transaction (donc la "table de file d'attente" dédiée).

EG, demandez à votre processus d'interrogation d'exécuter un lot comme celui-ci:

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

Attendre jusqu'à 25 secondes pour qu'une ligne apparaisse dans le tableau, interrogation toutes les secondes. À l'expiration, il renvoie simplement un ensemble de résultats vide.

sans interroger la table

La chose la plus simple consiste alors à utiliser Service Broker, ainsi qu'une procédure d'activation interne qui appelle le Python via xp_cmdshell, ou un processus externe qui boucle sur un blocage RECEIVE sur la file d'attente du service broker cible. C'est ainsi que Database Mail fonctionne sous le capot.

David Browne - Microsoft
la source
Il y a un bel article détaillé sur la configuration de Service Broker .
mustaccio
2

Pour minimiser l'impact de l'exécution synchrone du script Python à partir de votre déclencheur, vous pouvez encapsuler votre code Python dans 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()

Vous pouvez ensuite envoyer une requête HTTP depuis votre déclencheur vers le démon ci-dessus, comme illustré par exemple dans ce SO Q&A . Le gestionnaire de requêtes peut même générer un thread distinct pour exécuter votre logique Python de manière asynchrone.

mustaccio
la source
Bonne réponse!!! La plupart des applications mgr du milieu des années 90 (sur lesquelles j'ai travaillé) interrogeaient la base de données, avec un intervalle d'interrogation.
suréchange le