EMQX GCP Pub/Sub 生产者连接器健康检查失败诊断unhealthy_target 与状态码解析【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址: https://gitcode.com/gh_mirrors/em/emqx导读本文围绕 EMQX 开源仓库中apps/emqx_bridge_gcp_pubsub应用对 GCP Pub/Sub Producer 连接器Connector健康检查失败的增强诊断展开。你将了解到 EMQX 在创建/探测 GCP Pub/Sub 生产者动作Action时如何通过一次pubsub_get_topic预检调用识别出 Topic 不存在、权限不足、凭据错误等具体根因并掌握对应的 HTTP 状态码、错误消息结构与health_check_interval等资源参数的实际含义可直接用于日常排障与配置调优。背景一个专为诊断而生的变更在 changes/ee/fix-14427.en.md 中记录了这样一项变更Added more information about health check failures in GCP PubSub Producer connector.为 GCP PubSub Producer 连接器的健康检查失败补充了更多信息。该变更的落点在于当 EMQX 检查 GCP Pub/Sub 生产者连接器/动作的健康状态时不再只给出笼统的连接失败而是能够区分出Topic 不存在、对该 Topic 无权限、凭据无效等具体原因从而显著缩短排障路径。下文将结合仓库源码与测试用例逐层拆解这条诊断链路是如何实现的、错误信息长什么样、以及如何配置与复现。健康检查的触发时机与配置项在 EMQX 中连接器和动作Action的健康状态由资源层统一管理。GCP Pub/Sub 连接器相关配置定义在 emqx_bridge_gcp_pubsub.erl 中其中consumer_resource_opts小节明确了资源健康检查的关键参数fields(consumer_resource_opts) - ResourceFields emqx_resource_schema:create_opts( [{health_check_interval, #{default 30s}}] ), SupportedFields [ health_check_interval, request_ttl ], ...要点如下health_check_interval健康检查间隔默认30s。资源层会按该周期对连接器/动作执行健康检查测试用例中常将其调小为1s以加速验证参见 emqx_bridge_gcp_pubsub_producer_SUITE.erl。request_ttl请求超时/有效期与健康检查的探测请求配合使用用于控制单次探测请求的等待时长。连接器级健康检查连接器的健康状态由on_get_status回调驱动emqx_bridge_gcp_pubsub_impl_producer.erlon_get_status(_InstanceId, #{client : Client} _State) - emqx_bridge_gcp_pubsub_client:get_status(Client).底层实现位于 emqx_bridge_gcp_pubsub_client.erlget_status(#{connect_timeout : _, pool_name : _} State) - case do_get_status(State) of ok - ?status_connected; {error, Reason} - ?SLOG(error, #{ msg gcp_client_get_status_failed, state State, reason Reason }), {?status_disconnected, Reason} end.健康检查的判定流程do_get_status依次包含三个环节check_token_exists(State)校验 OAuth2 访问令牌缓存是否存在且有效ehttpc:check_pool_integrity(ResourceId)校验 HTTP 连接池完整性对池内每个 worker 执行ehttpc:health_check(Worker, Timeout)失败时通过?SLOG_THROTTLE输出gcp_client_ehttpc_health_check_failed日志并附上resource_id、reason、worker与wait_time等上下文见 emqx_bridge_gcp_pubsub_client.erl。任何一环失败都会导致连接器状态变为{?status_disconnected, Reason}同时将详细原因写入错误日志——这正是补充更多健康检查失败信息在连接器层面的体现。动作级Channel健康检查与连接器不同生产者动作在安装on_add_channel时就会做一次针对目标 Topic 的预检。这一步在 emqx_bridge_gcp_pubsub_impl_producer.erl 的install_channel/2中实现install_channel(ActionConfig, ConnectorState) - #{parameters : #{ attributes_template : AttributesTemplate, ordering_key_template : OrderingKeyTemplate, payload_template : PayloadTemplate, pubsub_topic : PubSubTopic }, resource_opts : #{request_ttl : RequestTTL}} ActionConfig, #{client : Client} ConnectorState, case emqx_bridge_gcp_pubsub_client:pubsub_get_topic(PubSubTopic, Client, #{ request_ttl RequestTTL }) of {error, #{status_code : 404}} - {error, {unhealthy_target, Topic does not exist}}; {error, #{status_code : 403}} - {error, {unhealthy_target, Permission denied for topic}}; {error, #{status_code : 401}} - {error, {unhealthy_target, Bad credentials}}; {error, Reason} - {error, Reason}; {ok, _} - {ok, #{...}} end.可以看到健康检查预检通过对 GCP Pub/Sub 的GET /v1/projects/project-id/topics/topic-name接口发起一次探测并根据返回状态码把失败原因翻译成人类可读、结构化的错误HTTP 状态码语义unhealthy_target 中的错误文本404Topic 不存在Topic does not exist403对目标 Topic 无权限Permission denied for topic401凭据无效Bad credentials其他错误网络、超时等透传原始Reason这段预检逻辑的探测请求封装在emqx_bridge_gcp_pubsub_client:pubsub_get_topic/3中emqx_bridge_gcp_pubsub_client.erl它会先解析 Topic 归属的项目再构造GET /v1/projects/project/topics/topic请求执行同步查询。错误信息的对外呈现probe 接口与 API 响应上述{unhealthy_target, Topic does not exist}这样的结构化错误并不会只停留在日志里。EMQX 的 API 层会把动作健康检查失败原因返回给调用方尤其是probe探测接口——即创建动作前先验证配置是否可用的接口。在 emqx_bridge_gcp_pubsub_producer_SUITE.erl 的t_bad_topic用例中对该行为做了完整断言t_bad_topic(TCConfig) - ?check_trace( begin {201, _} create_connector_api(TCConfig, #{}), ?assertMatch( {201, #{status : disconnected}}, create_action_api(TCConfig, #{ parameters #{pubsub_topic i-dont-exist} }) ), ProbeRes probe_action_api( TCConfig, #{parameters #{pubsub_topic i-dont-exist}} ), ?assertMatch({400, _}, ProbeRes), {400, #{message : Msg}} ProbeRes, ?assertMatch(match, re:run(Msg, unhealthy_target, [{capture, none}]), ...), ?assertMatch(match, re:run(Msg, Topic does not exist, [{capture, none}]), ...), ok end, [])从该测试可以提炼出三条可以直接指导排障的事实创建动作时若配置的pubsub_topic不存在如示例中的i-dont-exist动作创建接口返回201但动作状态为disconnected即创建成功、但目标不可用probe 接口对同样的错误配置发起探测API 返回HTTP 400且响应体的message字段同时包含unhealthy_target与Topic does not exist两个关键片段让客户端能直接拿到根因这也意味着在 Dashboard 或通过 API 创建/测试 GCP Pub/Sub 生产者动作时看到unhealthy_target与具体原因文本即可直接定位是 Topic 路径、权限还是凭据问题无需再去抓取底层 HTTP 日志。补充信息背后的完整诊断链路综合以上源码与测试可以梳理出该变更生效后的完整诊断链路创建/探测生产者动作 │ ▼ on_add_channel / probe ──► pubsub_get_topic(Topic, Client, ReqOpts) │ │ │ ▼ │ GET /v1/projects/project/topics/topic │ │ │ ▼ │ 解析 HTTP 状态码 │ 404 ─► unhealthy_target: Topic does not exist │ 403 ─► unhealthy_target: Permission denied for topic │ 401 ─► unhealthy_target: Bad credentials │ 其他 ─► 透传原始错误 │ │ ▼ ▼ 状态变为 disconnected 日志 API message 返回可读根因关于 Topic 路径解析的补充值得留意的是pubsub_topic字段既支持裸 Topic 名也支持完整路径。pubsub_topic_validator/1emqx_bridge_gcp_pubsub.erl与resolve_topic/2emqx_bridge_gcp_pubsub_client.erl共同实现以下规则传入裸名称如my-topic时解析为服务账号所属项目下的 Topic传入完整路径projects/project-id/topics/topic-name时解析为指定项目下的 Topic可跨项目指向其他 GCP 项目其他格式在校验阶段即被拒绝提示must be either a topic name or a fully-qualified topic path projects/project-id/topics/topic-name。因此当健康检查报告Topic does not exist时除了确认 Topic 是否真的创建外还应检查所填的是否为裸名/完整路径以及该路径指向的项目与服务账号项目是否一致。测试 emqx_bridge_gcp_pubsub_producer_SUITE.erl 也验证了动作发布并做健康检查的对象是 Topic 路径所指项目的 Topic 而非服务账号项目的 Topic这一行为。实战排障对照表结合上述实现将常见故障与可采取的动作汇总如下现象API message / 日志根因方向排查与处置建议unhealthy_targetTopic does not exist404Topic 未创建或 Topic 路径写错/项目解析错误在 GCP 控制台确认 Topic 存在核对pubsub_topic是裸名还是projects/id/topics/name全路径确认指向项目无误unhealthy_targetPermission denied for topic403服务账号缺少对目标 Topic 的pubsub.topics.get等权限为服务账号授予 Pub/Sub Publisherroles/pubsub.publisher或更细粒度的 IAM 权限并确认授权作用于 Topic 所属项目unhealthy_targetBad credentials401service_account_json无效、过期或格式有误检查连接器配置中的service_account_json是否完整有效确认密钥未轮换/失效可重新生成并更新其他{error, Reason}网络不通、超时、服务不可达检查 EMQX 节点到pubsub.googleapis.com:443或自建 Pub/Sub Emulator 地址的连通性结合connect_timeout、request_ttl参数调整探测超时关键配置参数速览本主题涉及的核心配置参数定义于 emqx_bridge_gcp_pubsub.erl参数默认值说明connect_timeout15s连接超时毫秒时长格式pool_size8HTTP 连接池大小pipelining100单连接流水线请求数上限max_retries2请求最大重试次数request_timeout15s请求超时自 5.0.1 起标记为 deprecatedservice_account_json无服务账号 JSON敏感字段支持 JSON 字符串或 Map 自动转换health_check_interval30s资源健康检查间隔见consumer_resource_optsrequest_ttl无单次探测请求的 TTL与健康检查协同工作需要说明的是以上默认值与字段定义以当前仓库源码为准request_timeout已被标记为 deprecated新配置应优先关注request_ttl与connect_timeout的配合。小结fix-14427这项变更为 GCP PubSub Producer 连接器的健康检查注入了可读、可定位的失败信息连接器层通过令牌校验、连接池完整性检查与ehttpc:health_check三阶段探活动作层通过pubsub_get_topic预检把 404/403/401 分别映射为Topic does not exist、Permission denied for topic、Bad credentials三类明确的unhealthy_target错误。这一设计让用户在创建动作、调用 probe 接口或查看资源状态时第一时间就能区分Topic 没建权限不够凭据不对三类高频问题而无需深入抓取底层请求日志。如需进一步阅读源码细节可重点查看 emqx_bridge_gcp_pubsub_impl_producer.erl、emqx_bridge_gcp_pubsub_client.erl 以及测试用例 emqx_bridge_gcp_pubsub_producer_SUITE.erl。【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址: https://gitcode.com/gh_mirrors/em/emqx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考