我正在创建一个由python flask制作的网络应用程序..我想要的是,如果我创建了发票,它会在续订日期自动发送电子邮件,以通知发票已续订等等。请注意更新每3个月发生一次代码如下:
def some_method(): // An API Enpoint that adds an invoice from a request
// Syntax that inserts the details to the database
// Let's assume that the the start of the renewal_date is December 15, 2016
如何实现自动电子邮件执行?没有在后端施加太大的压力?因为我猜测如果有300张发票,那么服务器可能会有压力
答案 0 :(得分:2)
"自己写。"不,真的。
保留要发送的发票的数据库表。每张发票都有一个状态(值pending
,sent
,paid
,...)和发票日期(可能在将来)。使用cron
或类似信息定期运行(例如1 /小时,1 /天)一个程序,该程序查询表中发票日期/时间已到达/已通过的待处理发票,但尚未发送任何发票。此开票流程会发送发票,更新状态并完成。此Invoicer实用程序不会成为Flask Web应用程序的组成部分,但可以作为支持程序使用它。
为什么呢?这是一种简单直接的方法。它将发票代码保存在Python中,接近您选择的应用程序语言和数据库。它不需要太多的外部系统或中间件的偏移。使用与编写应用程序本身相同的数据库,查询和技能,可以直接调试和监控。简单,直接,可靠,完成。什么不爱?
现在,我完全理解"自己写一下"推荐与典型的"买不建立#34;教义。但我尝试了所有主要的替代方案,例如cron和Celery;我使用创收网络应用程序的经验表明,他们不是几百个长期发票活动的方式。
TL; DR - 为什么不是Cron和Celery?
cron
及其后期等价物(例如launchd
或Heroku Scheduler)会产生重复发生的事件。每隔10分钟,每小时,每天一次,每隔一个星期二凌晨3:10 UTC。他们通常不会在未来的某个时间和日期X解决这个问题""问题,但它们非常适合定期工作。
现在最后一句话并非严格属实。它描述了cron
及其部分替代品。但是,即使是传统的Unix也会将at作为旁边的cron
,而一些cron
后续(例如launchd
,systemd
)捆绑重复和将来的事件一起安排(以及其他厨房用具和众所周知的水槽)。 Evens所以,有一些问题:
cron
的调度程序缺乏强有力的处理和错过"事件或"尽早制作它们。"从技术角度来说,这可能是一个让人失望的人。"说事件触发了汇款 - 或者在您的情况下,发票发票。您有数百张发票,发出这些发票可能是关键业务。系统级调度程序与您的操作需求之间的能力差距可能非常痛苦,特别是在您扩展时。好的,那些将这些事件推入像Celery这样的外部事件调度程序呢?这是一个很多更好的主意。 Celery旨在运行大量的应用程序事件。它支持各种后端引擎(例如RabbitMQ),这些引擎在实践中经过验证,可以处理成千上万的数以千计的事件,并且它具有用户界面选项,可以帮助处理事件众多事件。到现在为止还挺好!但是:
cron
等一样,Celery长投掷事件与正常的应用更新和重启周期非常相似。这取决于环境,但发生在像Heroku这样的流行云服务上。 芹菜问题并非完全无法解决或致命,但长时间延迟的事件并不是一样的好消息!哇!芹菜让一切都变得更好!"你为成群的近期事件所获得的魔力。你必须成为Celery,RabbitMQ等工程师和看护人。只需安排几百张发票,这是一个很高的价格和很多工作。
总结:虽然未来的发票安排似乎可以解决问题,但在实践中,将该功能保留在您的主应用程序代码中(而不是直接在您的Flask Web应用程序中,它会更容易,更快速,更强大)作为一个相关的实用程序),并且只是提出让我每天运行N次"低级别的tickler到系统级作业调度程序。
答案 1 :(得分:1)
您可以在Linux中使用crontab,语法如下所示
crontab -e
1 2 3 4 5 /path/to/command arg1 arg2
或许您可以查看Celery,我认为它是处理任务队列的好工具,您可以在这里找到有用的东西。celery.schedules
Schedule Tasks on Linux Using Crontab
HowTo: Add Jobs To cron Under Linux or UNIX?
How to Schedule Tasks on Linux: An Introduction to Crontab Files
答案 2 :(得分:0)
如果我理解正确,您需要在生成发票时获取日期,然后再添加3个月(90天)。您可以在Python中使用datetime.timedelta(days=90)
。请看一下:Adding 5 days to a date in Python。
从那里,你理论上可以生成一个Threading.timer()
的线程(如下所示:Python - Start a Function at Given Time),但我建议不要在这部分使用Python,因为你提到,它会给服务器带来不必要的压力(更不用说服务器出现故障,你失去了所有的日程安排)。
选项A(为每张发票安排任务):
使用操作系统将来安排任务会更好。如果你的后端是基于Linux的,那么Cron应该可以正常工作。看看这个想法:How to setup cron to run a file just once at a specific time in future?。就个人而言,我喜欢this answer,它建议在/etc/cron.d
为每个任务创建一个文件,让脚本在执行完毕后删除自己的文件。
选项B(每天检查是否应发送提醒):
我知道这不是你问的问题,但我也建议把它作为一项日常工作处理起来可能更干净。您可以安排这样的每日cron作业:
0 22 * * * /home/emailbot/bin/send_reminder_emails.py
所以,在这个例子中,每天,每个月,每周的每个星期的0,22小时(晚上10点),检查我们是否应该发送提醒电子邮件。
在send_reminder_emails.py脚本中,您可以检查需要“今天”发送的任何提醒的记录(可能是JSON或YML文件,或您的数据库,或自定义格式)。如果没有,则脚本退出,如果有,则向列表中的每个人发送提醒。 (可选)您可以在提醒过期时定期清理文件中的条目,也可以定期清理。
然后,您需要做的就是每次生成发票时都在提醒文件中添加一个条目。
with open("reminder_list.txt", "a") as my_file:
my_file.write("Invoice# person@email.com 2016-12-22")
此方法的另一个好处是,如果您的服务器因维护而关闭,您可以通过检查电子邮件日期是否已过datetime.datetime.now() >= datetime(2016,12,22)
来保留条目并立即发送。如果你这样做,你还需要保留一个真/假标志,指示电子邮件是否已经发送(这样你就不会向客户发送垃圾邮件)。