-4

我重用 http 客户端连接来对单个端点进行外部调用。该程序的摘录如下所示:

var AppCon MyApp

func New(user, pass string, platformURL *url.URL, restContext string) (*MyApp, error) {
  if AppCon == (MyApp{}) {
      AppCon = MyApp{
          user:        user,
          password:    pass,
          URL:         platformURL,
          Client:      &http.Client{Timeout: 30 * time.Second},
          RESTContext: restContext,
      }

      cj, err := cookiejar.New(nil)
      if err != nil {
          return &AppCon, err
      }

      AppCon.cookie = cj
  }

    return &AppCon, nil
}

// This is an example only. There are many more functions which accept *MyApp as a pointer.
func(ma *MyApp) GetUser(name string) (string, error){
   // Return user
}

func main(){   
    for {
      // Get messages from a queue 
      // The message returned from the queue provide info on which methods to call
      // 'm' is a struct with message metadata

      c, err := New(m.un, m.pass, m.url)

      go func(){
        // Do something i.e c.GetUser("123456")
      }()
    }
}

我现在需要建立与通过队列消息接收的不同端点/凭据的客户端连接。

我预见的问题是我不能简单地修改AppCon新的端点详细信息,因为返回了一个指向的指针MyApp,从而导致重置c. 这可能会影响对非预期端点进行 HTTP 调用的 goroutine。为了使事情变得不简单,该程序并不意味着知道端点(我正在考虑使用switch语句),而是通过队列消息接收它需要的东西。

鉴于我提出的问题是正确的,有没有关于如何解决它的建议?

编辑 1

根据提供的反馈,我倾向于相信这将解决我的问题:

  1. 删除使用 Singleton 的MyApp
  2. 解耦 http 客户端,MyApp使其可以重用
var httpClient *http.Client

func New(user, pass string, platformURL *url.URL, restContext string) (*MyApp, error) {

    AppCon = MyApp{
          user:        user,
          password:    pass,
          URL:         platformURL,
          Client:      func() *http.Client {
      if httpClient == nil {
        httpClient = &http.Client{Timeout: 30 * time.Second}
      }
        return httpClient
    }()
          RESTContext: restContext,
      }

    return &AppCon, nil
}

// This is an example only. There are many more functions which accept *MyApp as a pointer.
func(ma *MyApp) GetUser(name string) (string, error){
   // Return user
}

func main(){   
    for {
      // Get messages from a queue 
      // The message returned from the queue provide info on which methods to call
      // 'm' is a struct with message metadata

      c, err := New(m.un, m.pass, m.url)

      // Must pass a reference
      go func(c *MyApp){
        // Do something i.e c.GetUser("123456")
      }(c)
    }
}
4

1 回答 1

0

免责声明:这不是对您问题的直接回答,而是试图引导您找到解决问题的正确方法。

  • 尽量避免为您使用单例模式MyApp。此外,New具有误导性,它实际上并不是每次都创建一个新对象。相反,您可以每次都创建一个新实例,同时保留 http 客户端连接。
  • 不要使用这样的结构:AppCon == (MyApp{}),有一天你会在你的腿上这样做。改为使用指针并将其与nil.
  • 避免竞争条件。在您的代码中,您启动一​​个 goroutine 并立即进行for循环的新迭代。考虑到您重用整个MyApp实例,您基本上引入了竞争条件。
  • 使用 cookie,您可以使连接有点有状态,但您的任务似乎需要无状态连接。这种方法可能有问题。
于 2020-03-02T08:30:17.820 回答