应用程序的邮件程序系统是否应该在一个单独的渠道中运行,如本例所示?

时间:2015-09-04 17:11:15

标签: go architecture channel

想象一下拥有大量不同路由的网络服务。其中一些会触发发送给用户的交易电子邮件。初始化邮件程序实例似乎很奇怪,例如每次请求想要发送内容时使用github.com/aws/aws-sdk-go/service/sns的内容。

相反,我假设有一个邮件程序实例,所有内容都发生在message发布到的单独频道上。

实施例

我创建了一个说明问题的简单示例。全局Mailer实例配置一次,Index处理程序请求通道并传递Message

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

// Message is the custom type used to pass the channel
type Message struct {
    To      string
    Subject string
    Body    string
}

// Mailer is responsible to send out emails
type Mailer struct{}

// send sends out the email
func (m *Mailer) send(message Message) {
    fmt.Printf("Sending email to:`%s`\nSubject: %s\n%s\n\n", message.To, message.Subject, message.Body)
}

// Messages returns the channel to which messages can be passed
func (m *Mailer) Messages() chan<- Message {
    cm := make(chan Message)

    go func() {
        msg := <-cm
        m.send(msg)

        close(cm)
    }()

    return cm
}

// mailer is a global var in this example, would probably be part of some
// sort of app context that's accessible from any handler.
//
// Note the mailer is NOT handler-scoped.
var mailer = Mailer{} // would this be thread-safe?

// Index handler
func Index(w http.ResponseWriter, r *http.Request) {
    m := Message{"email@example.com", fmt.Sprintf("visited `%s`", r.URL.Path[1:]), "Lorem ipsum"}
    mailer.Messages() <- m

    fmt.Fprintf(w, "Sent out email with subject line `%s`\n", m.Subject)
}

func main() {
    http.HandleFunc("/", Index)

    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }

    if err := http.ListenAndServe(":"+port, nil); err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

输出

Visting http://localhost:8080/hello-world将呈现......

  

发送主题为“visited`hello-world``

的电子邮件

...并记录

  

向`email @ example.com`发送电子邮件:
    参观了'hello-world`
    Lorem ipsum

问题

  1. 这是正确的方法吗?
  2. 是否是线程安全的 - 如果不是如何使其线程安全?

1 个答案:

答案 0 :(得分:1)

在这个例子中你并没有真正做任何事情,但是通过通道传递消息总是安全的 - 通道是该语言中的基本并发原语之一。根据{{​​1}}实际最终做的事情,你会让自己对竞争条件的可能性持开放态度。另一种处理方法是让react-router从单个频道接收。

send