从插入触发器启动python脚本


10

我们有一段不错的python,它可以发送一些电子邮件并与云系统进行交互。工作良好。但是我们必须每隔几分钟触发一次以轮询数据库。出于业务目的,我们确实需要实时启动python脚本,因此没有轮询延迟。(这为与客户通电话的销售人员提供服务。)

我们真的不希望有1分钟的轮询循环。或30秒。我们希望该记录显示在数据库中,并让事情立即发生。

快速实现此目标的快速方法是在将特定记录类型插入表中时触发它。

我们可以从触发器中触发python脚本吗?

根据下面的Aaron注释,我们知道这是Very Bad Thing™,但是此表的使用很少(每天插入0-12次)。轮询表无法满足我们的业务需求(我们需要.py立即运行-它做的不仅仅是发送电子邮件)。

我们认为,满足业务需求的一种方法是在SQL Server上设置python的.net版本,然后让T-SQL以调用C#的方式调用python脚本... 但是我们不知道如何实际做到这一点!(请问这个问题)。

文档/详细信息?


我问了有关堆栈溢出的后续问题:如何在SQL Server中创建Python CLR过程?


问题下的问题:您有一块python。您希望它从SQL触发器中触发,但是您知道这是一件很糟糕的事情。那么,如何在不使用python代码的情况下真正实现相同的效果的SQL操作呢?

解决此需求的非触发,非轮询方法是什么?

(相同的效果=“在表中发生插入/更新/删除,并且在db事件发生后2秒内触发了python脚本,而没有轮询表”)


五年后您要更改问题吗?充满冲突。轮询表不满足您的业务需求,因为py需要立即运行,但是在更新中您说2秒的延迟是可以接受的吗?令人困惑。如果2秒的延迟是可以接受的,那么我认为是对表进行轮询。
亚伦·伯特兰

1
@AaronBertrand我同意这个问题并不符合每个人对现实的看法。但是,如果我们花一点时间,并假设发问者很聪明,并且真诚地要求他进行非实际触发但行为类似触发的任务,我们(作为SE社区)可以帮助找到一种方法fwd(或忽略该问题,实际上并没有使需求/问题消失)。wi
Jonesome恢复莫妮卡

很好,但是您必须选择要解决的问题,然后解决问题(或者,如果5年前的答案是可以接受的,那么今天又不再是可以接受的,则可以开始一个新的问题,是否是因为您的要求此后有所改变) )。目前,您说不想轮询触发,也要说必须立即进行,并且延迟2秒即可。
亚伦·伯特兰

现在,在这种情况下,NoSQL不会像DBMS那样方便,因为DBMS可以管理触发器并作为应用程序层(不仅仅是数据存储)做出贡献
过度交换

@samsmith您是否回答了这个问题?
外汇兑换

Answers:


12

不要让用户事务等待(希望!)成功完成Python脚本。您的整个交易都坐在那儿,等待这个外部过程运行,尝试发送邮件,等等。我怀疑电子邮件真的必须立即发出-特别是鉴于您无法控制它在路由时的任何延迟仍然会转到收件人的收件箱。如果时间安排如此重要,为什么不更频繁地运行该过程呢?

请对此技巧进行浏览

如果您确实确实希望以错误的方式执行此操作,则可以启用xp_cmdshell并退出。

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

现在,假设用户有权访问xp_cmdshell和/或SQL Server服务帐户可以看到python脚本存储的文件夹,那么您应该能够在触发器中执行此操作:

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

顺便说一句,您应该在问题中声明您知道这是一件非常不好的事情TM,但是无论出于何种原因,您都不关心它。我仍然认为即使您从触发器中触发了此操作,您也不会获得预期的实时性。您是否考虑过数据库邮件而不是python?


亚伦,您的观点都是正确的,但这是我的问题。我想从触发器中触发python,而我对此没有任何疑问。(我可以让真实表上的触发器将值推入“作业”表中,而触发器在“作业”表上运行python ...)
Jonesome Reinstate Monica 2013年

4
另外,您的触发器->其他表->其他触发器的想法仍然遇到相同的问题,只是现在情况更糟。原始事务仍必须等待所有级联活动完成。
亚伦·伯特兰

好电话RE级联问题。不会去那里!
Jonesome恢复莫妮卡

OP得以增强,以重新
构想

2

“插入/更新/删除发生在表中,并且在db事件后2秒内触发了python脚本,

首先,如果您使用触发器将消息写入专用于此目的的表中,则可以持续等待1秒甚至更少的时间来运行池化过程。关键是使轮询查询足够便宜(<1ms),并且不干扰任何其他事务(因此,使用专用的“队列表”)。

EG让您的轮询过程像这样运行批处理:

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

要等待25秒以使表中出现一行,每秒轮询一次。在超时时,它仅返回一个空结果集。

不轮询表

然后,最简单的方法是将Service Broker与内部激活过程(通过xp_cmdshell调用Python)或在目标Service Broker队列上的阻塞RECEIVE上循环的外部进程一起使用。这就是数据库邮件的幕后工作方式。


关于服务代理设置,有一篇很好的详细文章
mustaccio

2

为了最大程度地减少从触发器同步运行Python脚本的影响,可以将Python代码包装到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()

然后,您可以将触发器中的HTTP请求发送到上面的守护程序,如本SO Q&A中所示。请求处理程序甚至可以生成单独的线程以异步运行Python逻辑。


不错的答案!!!90年代中期(我工作的)mgr应用程序中的大多数都以轮询间隔轮询数据库。
汇率过高
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.