在Absinthe Middleware中调用FunWithFlags出现ets.lookup ArgumentError
问题原因
你的报错根源是调用时机错误:Absinthe的middleware/3回调属于编译期执行逻辑,仅在Schema模块编译时运行,用于组装整个Schema的中间件列表,并不会在每次GraphQL请求时触发。
你直接在middleware/3顶层调用FunWithFlags.enabled?(:some_flag),相当于代码编译阶段就会执行这个调用,此时应用还没完成启动流程,FunWithFlags依赖的ETS缓存表、Redis/数据库连接都还没初始化,自然会抛出ETS查找失败的错误。
你修改配置关闭缓存不生效也是同理:编译阶段配置还没完成加载,哪怕缓存关了,此时连持久化存储的连接都不存在,调用依然会失败。
解决方法
把特征开关的判断逻辑移到运行时执行的中间件函数内部即可,middleware/3回调仅用于注册中间件,不要在这一层执行运行时逻辑。
两种常用实现方案:
方案1:直接匿名函数实现
defmodule MyApp.Schema do use Absinthe.Schema # ... 其他Schema代码 def middleware(middleware, field, object) do # 编译阶段仅组装中间件列表,不执行开关判断 flag_check_middleware = fn resolution -> # 这里的逻辑会在每次请求处理时运行,此时应用已完全启动 if FunWithFlags.enabled?(:some_flag) do # 开关开启时的处理逻辑 resolution else # 开关关闭时的处理逻辑,比如返回错误 Absinthe.Resolution.put_result(resolution, {:error, "该功能暂未开放"}) end end [flag_check_middleware | middleware] end end
方案2:封装为独立中间件模块(更适合复用)
# 单独定义中间件模块 defmodule MyApp.Middleware.SomeFlagCheck do @behaviour Absinthe.Middleware @impl true def call(resolution, _opts) do if FunWithFlags.enabled?(:some_flag) do resolution else Absinthe.Resolution.put_result(resolution, {:error, "feature not available"}) end end end # 在Schema中注册 defmodule MyApp.Schema do use Absinthe.Schema # ... 其他代码 def middleware(middleware, field, object) do # 仅注册中间件,不执行实际判断 [MyApp.Middleware.SomeFlagCheck | middleware] end end
如果你的需求确实是编译阶段根据开关做分支逻辑裁剪,可以直接使用Elixir自带的编译时环境变量,不要依赖FunWithFlags这类运行时特征开关工具。
内容的提问来源于stack exchange,提问作者catra
相关产品推荐
相关产品推荐

