Go语言 有关如何使用Service Weaver设置多个不同侦听器的问题

evrscar2  于 2023-09-28  发布在  Go
关注(0)|答案(1)|浏览(133)

我一直在玩Service Weaver,因为它已经发布了一段时间,我很好奇我们应该如何使用它设置多个侦听器。我的意图是,当我们部署应用程序时,web的处理程序和api的处理程序是分开运行的(作为示例)。代码如下:

  1. package main
  2. import (
  3. "context"
  4. "log"
  5. "sync"
  6. "github.com/ServiceWeaver/weaver"
  7. "github.com/labstack/echo/v4"
  8. "github.com/labstack/echo/v4/middleware"
  9. )
  10. type Server struct {
  11. weaver.Implements[weaver.Main]
  12. apiServer weaver.Ref[APIServer]
  13. webServer weaver.Ref[WebServer]
  14. }
  15. type APIServer interface {
  16. Serve(context.Context) error
  17. }
  18. type apiServer struct {
  19. weaver.Implements[APIServer]
  20. api weaver.Listener
  21. }
  22. func (a apiServer) Serve(ctx context.Context) error {
  23. logger := a.Logger(ctx)
  24. e := echo.New()
  25. e.Listener = a.api
  26. e.Use(middleware.RequestID())
  27. e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
  28. LogStatus: true,
  29. LogURI: true,
  30. LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
  31. logger.Info("Request", "id", v.RequestID, "uri", v.URI, "status", v.Status, "size", v.ResponseSize)
  32. return nil
  33. },
  34. }))
  35. return e.Start("")
  36. }
  37. type WebServer interface {
  38. Serve(context.Context) error
  39. }
  40. type webServer struct {
  41. weaver.Implements[WebServer]
  42. web weaver.Listener
  43. }
  44. func (w webServer) Serve(ctx context.Context) error {
  45. logger := w.Logger(ctx)
  46. e := echo.New()
  47. e.Listener = w.web
  48. e.Use(middleware.RequestID())
  49. e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
  50. LogStatus: true,
  51. LogURI: true,
  52. LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
  53. logger.Info("Request", "id", v.RequestID, "uri", v.URI, "status", v.Status, "size", v.ResponseSize)
  54. return nil
  55. },
  56. }))
  57. return e.Start("")
  58. }
  59. func main() {
  60. if err := weaver.Run(context.Background(), serve); err != nil {
  61. log.Fatal(err)
  62. }
  63. }
  64. func serve(ctx context.Context, server *Server) error {
  65. wg := sync.WaitGroup{}
  66. wg.Add(2)
  67. go func() {
  68. defer wg.Done()
  69. server.apiServer.Get().Serve(context.Background())
  70. }()
  71. go func() {
  72. defer wg.Done()
  73. server.webServer.Get().Serve(context.Background())
  74. }()
  75. wg.Wait()
  76. return nil
  77. }

基本上,我只是设置了两个回声服务器,一个为每个组件。
为了它的价值,这是我的配置:

  1. [serviceweaver]
  2. binary = "./platform"
  3. [multi]
  4. listeners.api = { address = "localhost:12345" }
  5. listeners.web = { address = "localhost:54321" }
  6. [single]
  7. listeners.api = { address = "localhost:12345" }
  8. listeners.web = { address = "localhost:54321" }

当我在单个进程中运行它时,一切似乎都按预期工作。我看到了Web请求的日志条目,表明一切正常。当我在部署模式下运行它时(即,实际上执行多进程魔术),我只能发出1-2个请求,然后才能看到如下日志条目,然后响应通常不起作用:

  1. 2023/09/14 21:35:51 http: proxy error: context canceled

看起来我做错了什么,但这似乎是一个用例,将以某种方式得到支持,所以我想知道是否有一个适当的方法来解决这个问题。
谢谢你,谢谢

pcrecxhr

pcrecxhr1#

tl;drService Weaver目前还没有一个很好的方法来从非主组件运行HTTP服务器。我建议您将两个侦听器都移动到Server结构体中,并在serve函数中运行两个HTTP服务器。HTTP服务器可以调用其他组件上的方法。

  1. type Server struct {
  2. weaver.Implements[weaver.Main]
  3. api weaver.Listener
  4. web weaver.Listener
  5. }

详情

weaver multi部署器将每个组件复制两次,每个副本都在自己的操作系统进程中运行。考虑一下当APIServer组件在端口12345上请求网络侦听器时会发生什么。APIServer组件的两个副本不能同时侦听端口12345;只有一个OS进程可以在端口上侦听。为了解决这个问题,两个副本分别监听一个随机选择的端口,比如8000和9000。然后,weaver multi部署程序在端口12345上运行HTTP代理,将请求转发到端口8000和9000。
在您的应用程序中,主Server组件复制两次,serve函数运行两次,在每个副本上运行一次。在serve内部,当您调用apiServer.Get().Serve(context.Background())时,会随机选择APIServer的副本来执行Serve方法。如果幸运的话,两个方法调用被发送到两个不同的副本,那么一切都应该顺利运行。但是,如果两个方法调用都被发送到同一个副本,那么APIServer的一个副本正在运行HTTP服务器,而另一个则没有。
在这种情况下,代理将一半的请求转发到正在运行的HTTP服务器,另一半的请求转发到未侦听的侦听器。这会导致您看到的代理错误。
最后,请注意,当您使用go runweaver single deploy运行应用程序时,事情是正常的,因为没有代理,而且组件没有被复制。

展开查看全部

相关问题