Google app engine 如何确保使用任务队列时不会发送两次电子邮件?
我想更改我的GAE应用程序逻辑,并开始使用任务队列发送电子邮件 目前我有一个cron作业,每15分钟运行一次,读取要从数据存储发送的消息:Google app engine 如何确保使用任务队列时不会发送两次电子邮件?,google-app-engine,email,cron,task-queue,Google App Engine,Email,Cron,Task Queue,我想更改我的GAE应用程序逻辑,并开始使用任务队列发送电子邮件 目前我有一个cron作业,每15分钟运行一次,读取要从数据存储发送的消息: class SendMessagesHandler(webapp2.RequestHandler): def get(self): emails_quota_exceeded = models.get_system_value('emails_quota_exceeded') if emails_quota_excee
class SendMessagesHandler(webapp2.RequestHandler):
def get(self):
emails_quota_exceeded = models.get_system_value('emails_quota_exceeded')
if emails_quota_exceeded == 0 or emails_quota_exceeded == None:
messages = models.get_emails_queue()
for message in messages:
try:
...
email.send()
models.update_email_status(message.key.id()) # update email status indicating that the mail has been sent
except apiproxy_errors.OverQuotaError, error_message:
models.set_system_value(what='emails_quota_exceeded', val=1)
logging.warning('E-mails quota exceeded for today: %s' % error_message)
break
else:
logging.info('Free quota to send e-mails is exceeded')
如果我使用任务队列,那么我将得到如下结果:
for message in messages:
taskqueue.add(url='/sendmsg', payload=message)
在这个场景中,同一条消息可能会被发送两次(甚至更多次)——例如,如果它还没有发送,但cron作业是第二次执行的。
如果在将邮件添加到队列后立即更新电子邮件状态:
for message in messages:
taskqueue.add(url='/sendmsg', payload=message)
models.update_email_status(message.key.id()) # update email status indicating that the mail has been sent
那么,可能永远不会发送该消息。例如,如果在电子邮件发送过程中发生异常。请理解任务将重试,但如果今天超出配额,则重试将无济于事
我想我还可以在尝试发送任务队列之前重新读取每个消息的状态,但这将花费我额外的读取操作
处理该任务的最佳方法是什么?为任务指定一个名称,包括
key.id()
将防止任务被发送两次:
task_name = ''.join(['myemail-', str(mykey)])
try:
taskqueue.Task(
url="/someURL/send-single-email",
name=task_name,
method="POST",
params={
"subject": subject,
"body": body,
"to": to,
"from": from }
).add(queue_name="mail-queue")
except:
pass #throws TombstonedTaskError(InvalidTaskError) if tombstoned name used.
有时,您可能希望为具有相同密钥的消息发送后续电子邮件。因此,我建议在任务名称中添加date
或datetime
标记。这将允许您稍后发送相同密钥的其他消息:
task_name = ''.join(['myemail-', str(mykey), str(datetime.utcnow()-timedelta(hours=8))]).translate(string.maketrans('.:_ ', '----'))
阅读不是很贵。您可以向自己发送密件抄送,以确保已发送。@voscausa,是否每天复制100封邮件?不,谢谢:)有趣的方法,谢谢。但是,您从哪里找到了任务名称必须唯一的信息,以及任务名称不唯一时引发的
tombstonedtaskeror
?我没有立即看到文档,但任务名称正是为了这个目的而实现的,因此任务不会重复执行。另外,我应该补充一点,如果您想多次发送相同密钥的邮件,您还可以在任务名称中添加date
或datetime
。这将允许您稍后发送相同密钥的邮件<代码>''.join(['myemail-',str(mykey),str(datetime.utcnow()-timedelta(hours=8))).translate(string.maketrans('.:,'---'))Aah,我在那里找到了描述-。我已经编辑了答案,在任务名称中包含了datetime
戳的建议。嗯,有时,我得到的任务是现成的,而不是墓碑上的。。。看起来我应该抓住这两个例外。