在Pyramid .ini文件中配置不同的电子邮件后端

时间:2014-07-10 13:46:01

标签: python pyramid

我正在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函数将如何显示?

2 个答案:

答案 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)

自从一个月前提出问题以来,我已经做了一些阅读。它引导我找到两种可能的解决方案:

A)惯用金字塔

我们想解决两个问题:

  1. 如何为Pyramid应用程序全局设置在PasteDeploy配置文件(.ini文件)中指定的类
  2. 如何在运行时访问我们的课程而不用"经历"请求
  3. 要设置指定的类,我们应该在模块中定义一个includeme()函数,然后在.ini文件中指定模块作为pyramid.includes的一部分。在我们的includeme()函数中,我们使用config.registry.registerUtility()作为Zope Component Architecture的一部分来注册我们的类,并使用它实现的interface

    要在运行时访问我们的类,我们需要从registry.queryUtility()获得registry来调用pyramid.threadlocal.get_current_registry()

    这个解决方案有点像黑客攻击,因为它使用threadlocal来获取配置。

    B)懒惰模块全局

    我对此问题的个人解决方案更简单(并且可能不是线程安全的):

    # 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()