Go 模块依赖项固定 #

在使用 Go 开发服务器运行时代码时,应当了解 Go 插件模块如何加载到 Nakama 二进制文件中以及这对运行时模块有哪些约束。由于 Go 是一种经过编译和链接的语言,因此对于如何将最终二进制文件组合在一起有非常严格的要求。正是由于这个原因,必须以与您使用的 Nakama 服务器二进制文件相同的方式编译服务器运行时插件。这带来了一些限制,如果不满足这些限制,可能会导致几个常见错误。

下面是使用 Go 开发服务器运行时代码时可能遇到的一些常见陷阱,以及有效地避开这些陷阱的方法。

平台不匹配 #

问题 #

当您试图加载服务器运行时 Go 模块,而此模块是使用不同于 Nakama 二进制文件的平台编译的,您会遇到问题。 例如,不能将在 Linux 上编译的 Go 模块与在 macOS 上编译的Nakama 二进制文件一起使用。

1
2
3
4
5
6
7
{
  "level":"error",
  "ts":"...",
  "caller":"...",
  "msg":"Error initialising Go runtime provider",
  "error":"plugin.Open("/nakama/data/modules/backend.so"): /nakama/data/modules/backend.so: invalid ELF header"
}

解决方案 #

确保您为其编译 Go 服务器运行时模块的平台与编译 Nakama 二进制文件的目标平台匹配。

Go 运行库版本不匹配 #

问题 #

当您试图加载服务器运行时 Go 模块时,如果此模块是使用不同于 Nakama 二进制文件的 Go 运行库版本编译的,您会遇到问题。 例如,不能将使用 Go 版本 1.14 编译的 Go 模块与使用 Go 版本 1.15 编译的 Nakama 二进制文件一起使用。

1
2
3
4
5
6
7
8
{
  "level":"error",
  "ts":"...",
  "caller":"...",
  "msg":"Could not open Go module",
  "path":"/nakama/data/modules/backend.so",
  "error":"plugin.Open("/nakama/data/modules/backend"): plugin was built with a different version of package runtime/internal/sys"
}

解决方案 #

确保用编译 Nakama 二进制文件时所用的相同 Go 版本来编译 Go 服务器运行时模块。 使用您的 Dockerfile 中的 Nakamanakama-pluginbuilder Docker 映像的相同标记版本号,可以确保做到这一点。

Go 依赖项版本不匹配 #

问题 #

Nakama 二进制文件也在使用的任何直接或间接(可传递依赖项)依赖项/包必须是相同的版本。例如,如果您在服务器运行时模块中使用 github.com/gofrs/uuid 包的 3.3.0 版本,而 Nakama 二进制文件使用 4.0.0 版本,则您会遇到依赖项版本不匹配错误。

1
2
3
4
5
6
7
{
  "level":"fatal",
  "ts":"...",
  "caller":"...",
  "msg":"Failed initializing runtime modules",
  "error":"plugin.Open("/nakama/data/modules/backend"): plugin was built with a different version of package go.uber.org/zap/buffer"
}

解决方案 #

确保您使用的依赖项/包版本与要在其上运行服务器运行时模块的 Nakama 二进制文件相同。

如果与直接依赖项不匹配,则必须确保导入的是 Nakama 在 go.mod 文件中使用的同一版本。

在间接(可传递)依赖项发生依赖项不匹配的情况下,可以在 go.mod 文件中显式导入依赖项,然后使用 _(下划线)别名添加空白导入语句,使其成为直接依赖项,从而确保使用的是相同的版本,如下例所示。

1
2
3
import (
  _ "go.uber.org/zap"
)

完成此操作后,您可以运行 go mod vendor 命令,再次提供依赖项,确保您现在使用的是合适的版本。

搜索 Nakama 的 vendor/modules.txt 文件,寻找导致错误的包,有助于识别要固定到插件 go.mod 文件中的正确可传递依赖项版本。

此方法可能需要进行试错,因为 Nakama 实现的是快速失败方法,服务器将在遇到服务器运行时代码的第一个错误时据此抛出错误并关闭。这就是说,如果存在多个依赖项版本不匹配,您需要逐一进行修改。