我正在Pyramid开发一个相当基本的应用程序。该应用包含发送电子邮件的功能。目前我打算为此目的使用Sendgrid,但不想太紧密地耦合它。此外,我不希望在开发或测试期间发送任何电子邮件。我的解决方案是为每个提供程序创建轻量级中间件类,所有这些都提供send()
方法。
我想通过使用Configurator
对象可以实现松散耦合,但我还没有完成。
如果给出以下代码(请注意,我没有request
,因为我希望能够通过Celery调用此代码):
def send_email(sender, recipient, subject, contents):
emailer = get_emailer()
emailer.send(from=sender, to=receipient, subject=subject, body=contents)
假设我的development.ini包含get_emailer()
之类的内容,pyramid.includes = my_app.DumpToConsoleEmailer
函数将如何显示?
答案 0 :(得分:1)
你提到Celery会改变一切...... Celery并没有让它变得非常明显,但是Celery工作者是一个完全独立的过程,它对你的Pyramid应用程序一无所知,并且可能在不同的机器上运行,在Web应用程序创建任务后数小时执行任务 - 工作人员只需从队列中逐个执行任务并执行它们。没有请求,没有Configurator,没有WSGI堆栈,没有PasteDeploy从.ini
文件组装您的应用程序。
重点是 - 除非您明确说明,否则Celery工作人员不知道您的Pyramid流程是在开发或生产配置中启动的。甚至可以让一个工作人员从两个应用程序执行任务,一个在开发模式下运行,另一个在生产中运行:)
一种选择是在启动时明确地将配置传递给芹菜工作者(例如,通过在celeryconfig.py中声明一些变量)。然后,工作人员将始终使用相同的邮件程序完成所有任务。
另一个选择是传递" mailer_type"从Pyramid应用程序向每个任务的worker明确显示参数:
@task
def send_email(sender, recipient, subject, contents, mailer_type='dummy'):
emailer = get_emailer(mailer_type)
emailer.send(from=sender, to=receipient, subject=subject, body=contents)
在您的金字塔应用中,您可以将任何键/值对放在.ini
文件中,然后通过request.registry.settings
访问它们:
send_email.delay(..., request.registry.settings['mailer_type'])
答案 1 :(得分:0)
自从一个月前提出问题以来,我已经做了一些阅读。它引导我找到两种可能的解决方案:
我们想解决两个问题:
要设置指定的类,我们应该在模块中定义一个includeme()
函数,然后在.ini文件中指定模块作为pyramid.includes
的一部分。在我们的includeme()
函数中,我们使用config.registry.registerUtility()
作为Zope Component Architecture的一部分来注册我们的类,并使用它实现的interface。
要在运行时访问我们的类,我们需要从registry.queryUtility()
获得registry
来调用pyramid.threadlocal.get_current_registry()
。
这个解决方案有点像黑客攻击,因为它使用threadlocal
来获取配置。
我对此问题的个人解决方案更简单(并且可能不是线程安全的):
# In module MailerHolder:
class Holder(object):
mailer = None
holder = Holder()
def get_emailer():
return holder.mailer
#In module ConsoleMailer:
import MailHolder
class ConsoleMailer(object):
def send(self, **kwargs):
# Code to print email to console
def includeme(config):
MailHolder.holder.mailer = ConsoleMailer()