- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
lws_fi(Fault Injection)是 libwebsockets 提供的一套"系统性故障注入"机制:它在构建期通过LWS_WITH_SYS_FAULT_INJECTION选项开启,允许开发者在任意 lws 内部代码或用户代码中,按名称精准地合成 DNS 失败、连接失败、OOM、发送失败等难以在测试期自然复现的故障,从而验证错误处理路径的正确性。本文以 README.fault-injection.md 为骨架,结合 lws-fault-injection.h 与 fault-injection.c 的源码实现,系统讲解其设计原理、注入策略、命名空间继承、命令行接入方式,并给出完整的"已知内置故障名"清单,读者可据此在自己的 lws 应用或测试中直接复现各种故障场景。
上图展示了 lws_fi 的核心思想:用户准备好的故障规则(lws_fi_ctx_t)既可以绑定到lws_context,再经由lws_vhost、Secure Stream 等子对象逐级继承分发,也可以直接附加到客户端wsi或 Secure Stream 对象上;故障规则会沿匹配的每个层级向下传播到子对象(Faults propagate into subobjects at each matching level)。
为什么需要故障注入
日常开发中,绝大部分精力都花在"让系统在正常运行时做它该做的事"上。但若要保证质量,仅仅测试正常路径是不够的:那些低概率的错误分支(例如清理了尚未初始化的资源、忘记释放内存等)在测试期极难自然触发,却又往往是线上事故的根源。
lws 故障注入的目标就是解决这一痛点:它提供简单而强大的 API,允许在任何 lws 或用户代码中定向注入故障——包括早期初始化阶段,甚至 lws 初始化之前的用户代码。同时,lws 内部预置了大量"知名故障点"(well-known faults),可以从外部直接触发,无需修改被测代码。
核心概念:故障上下文与故障
故障注入的基本模型是:用户代码中的对象可以选择在自身内部初始化"故障上下文"(fault contexts),该上下文列出一组命名清晰的"故障"(faults),代表该代码支持、且用户希望注入的故障类型。
从 lws-fault-injection.h 可以看到两个核心数据结构:
typedef struct lws_fi { const char *name; /* 故障名称 */ const uint8_t *pattern; /* PATTERN 类型的位模式 */ uint64_t pre; /* DETERMINISTIC: 前置次数;PROBABILISTIC: 百分比;RANGE: 范围下限 */ uint64_t count; /* DETERMINISTIC: 注入次数;PATTERN: 位宽;RANGE: 范围上限 */ uint64_t times; /* 起始为 0,记录被查询的次数 */ char type; /* LWSFI_* 注入策略类型 */ } lws_fi_t; typedef struct lws_fi_ctx { lws_dll2_owner_t fi_owner; /* lws_fi_t 的双链表 */ struct lws_xos xos; /* xoshiro256 PRNG 状态(用于概率类注入) */ const char *name; } lws_fi_ctx_t;lws_fi_t:一条故障注入规则。每次注入请求都由它描述——注入哪个故障(name),以及"何时、以多大概率"注入(type+pre/count/pattern/times)。lws_fi_ctx_t:故障上下文,本质是lws_fi_t对象构成的链表(lws_dll2_owner_t fi_owner),内嵌一个 xoshiro256 伪随机数生成器状态,用于概率类决策。
这些"故障上下文"既可以直接嵌入对象(例如嵌入lws_context创建信息结构体、客户端连接信息结构体或 Secure Stream 信息结构体),也可以在对象创建后由系统对象携带。启用故障注入构建后,lws_context、lws_vhost、wsi、Secure Stream 句柄 / SSPC 句柄等关键系统对象都各自持有自己的lws_fi_ctx_t链表,可以挂接任意数量的lws_fi_t。
不过,直接向深层代码传参往往并不方便。例如:想在一个由 Secure Stream 创建的 wsi 上触发故障,该 wsi 由 lws 内部代码创建,与 Secure Stream 对象创建隔了一层,难以在创建时直接附加。因此 lws_fi 设计了基于命名空间路径(namespace paths)的定向继承方案:通常只需在 context 创建时列出想要的故障,它们就会在后续创建内部对象时被过滤分发到目标对象上。这也正是 fault-injection.c 中lws_fi_inherit_copy()的实现职责:按 scope(如vh)与 value(如myvhost)匹配vh=myvhost/前缀的规则,去掉匹配前缀后把副本挂到目标故障上下文。
构建选项:LWS_WITH_SYS_FAULT_INJECTION
lws_fi 通过一个构建期选项开启,默认关闭。在仓库的 CMakeLists.txt 中:
option(LWS_WITH_SYS_FAULT_INJECTION "Enable fault injection support" OFF)在编译 lws 时可通过-DLWS_WITH_SYS_FAULT_INJECTION=ON(或环境变量LWS_WITH_SYS_FAULT_INJECTION=1)打开。
需要强调的是默认行为零副作用:仅开启构建选项并不会影响代码运行,因为用户还必须显式地把想要的故障规则加入对象的故障上下文,故障才会被注入。此外,当该选项被关闭时,lws_fi()调用以及所有公开的lws_fi_user_*_fi()API 都会退化为编译期常量(0)(见 lws-fault-injection.h),相关判断代码会被编译器整体移除,零运行时开销。
在 lws 私有代码中集成故障条件
lws 私有代码中最简单的查询接口是:
lws_fi(fi_ctx, "name")- 返回
0:本次不需要注入故障; - 返回
1:本次应当合成该故障。
如果上下文中没有匹配"name"的规则,则总是返回0(不注入)。从 fault-injection.c 的实现可以看到,lws_fi()先在上下文的链表中查找同名规则,找不到直接返回 0;找到后按规则的type字段执行对应的决策逻辑,决定注入时还会打印一条告警日志Injecting fault %s->%s(这正是文档示例中日志的来源)。同时,若构建期禁用了故障注入,lws_fi()恒为常量0,代码中已有的lws_fi()调用可以原样保留、由编译器消除。
在用户代码中使用公开 API
用户代码无需理解故障上下文内部结构,只要手握一个常见对象(如 wsi)与规则名称即可查询。lws 提供了四组公开 API:
| 故障上下文持有者 | 公开 API |
|---|---|
| lws_context | int lws_fi_user_context_fi(struct lws_context *ctx, const char *rule) |
| wsi | int lws_fi_user_wsi_fi(struct lws *wsi, const char *rule) |
| ss 句柄 | int lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *rule) |
| sspc 句柄 | int lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *rule) |
它们的底层实现(fault-injection.c)其实就是对各自对象内嵌fic调用lws_fi()。
实战示例:minimal-http-client
仓库中的 minimal-http-client.c 在LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP回调中就有这样一段用户代码:
if (lws_fi_user_wsi_fi(wsi, "user_reject_at_est")) return -1;即:当规则wsi/user_reject_at_est命中时,在连接建立(ESTABLISHED)阶段主动返回-1拒绝连接。运行它并注入该故障:
lws-minimal-http-client --fault-injection 'wsi/user_reject_at_est'运行日志(示意)如下:
... [2021/03/11 13:41:05:2769] U: Connected to 46.105.127.147, http response: 200 [2021/03/11 13:41:05:2776] W: lws_fi: Injecting fault unk->user_reject_at_est [2021/03/11 13:41:05:2789] E: CLIENT_CONNECTION_ERROR: HS: disallowed at ESTABLISHED ...可以看到:连接本身成功(HTTP 200),随后故障被注入,连接因"在 ESTABLISHED 阶段被拒绝"而报出CLIENT_CONNECTION_ERROR,完整地走了一遍错误路径。
注入"时机"策略(LWSFI_* 类型)
lws_fi_t.type字段决定"何时注入"。API 会记录每次被查询的次数(times),并根据规则类型做出决策。源码 fault-injection.c 中的 switch 分支与头文件 lws-fault-injection.h 中的枚举一一对应:
| 注入规则类型 | 描述 |
|---|---|
LWSFI_ALWAYS | 无条件注入故障 |
LWSFI_DETERMINISTIC | 在前pre次不注入之后,接下来count次每次都注入 |
LWSFI_PROBABILISTIC | 以pre百分比概率注入 |
LWSFI_PATTERN | 以pre指向的位模式为参考(count个 bit),某次查询对应的 bit 为 1 则注入,指向静态数组 |
LWSFI_PATTERN_ALLOC | 同PATTERN,但模式数组为动态分配,故障上下文销毁时释放 |
LWSFI_RANGE | 不用于lws_fi()决策,而是在pre与count之间取一个伪随机数 |
实现细节:
- DETERMINISTIC:
times自增后,落在[pre, pre+count)区间内才注入; - PROBABILISTIC:调用
lws_xos_percent(&fic->xos, pre),即 PRNG 结果% 100 < pre时注入,100 恒真、0 恒假,中间线性缩放; - PATTERN / PATTERN_ALLOC:取
times++ % count作为 bit 下标,pattern[n >> 3] & (1 << (n & 7))为真则注入; - RANGE:返回
pre + (lws_xos(&fic->xos) % (count - pre)),从外部给定的123..456范围中取数(见lws_fi_range(),fault-injection.c)。
概率选择来源于 PRNG,其种子在 context 创建信息结构的故障注入上下文中设置。默认情况下,lws 辅助函数lws_cmdline_option_handle_builtin()把种子设为当前时间(微秒),但可以用--fault-seed <decimal>覆盖;命令行选项首次解析时会把实际生效的 PRNG 种子记入日志,便于复现。
向 lws_fi_ctx_t 添加故障规则
通常把lws_context作为定义故障的中央顶层位置。做法是在栈上准备好一个lws_fi_t,再逐一通过lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi)把它加入 context 创建信息结构体的.fic成员。lws_fi_add()会分配内存、拷贝传入的fi并挂到lws_fi_ctx_t链表上,因此传入的fi可以安全地离开作用域(fault-injection.c)。
当 context(或其他使用同一机制的对象)被创建时,它会从信息结构体的.fic导入全部故障并接管所有权,随后把.fic清空,使其可以安全地随 info 结构体离开作用域。这一"转移"由lws_fi_import()完成——它还会顺带继承源上下文的 PRNG 种子(fault-injection.c)。
配套的辅助 API 还有:
lws_fi_remove(fic, name):按名移除并销毁一条规则;lws_fi_destroy(fic):清空该上下文中所有已分配的规则(PATTERN_ALLOC模式会先释放模式数组);lws_fi_inherit_copy(fic_dest, fic_src, scope, value):按 scope/value 匹配父上下文中的命名空间规则并拷贝给子对象(命名空间机制的核心实现);lws_fi_deserialize(fic, sers):把字符串形式的规则(如"ss=captive_portal_detect/wsi/dnsfail(10%)")解析成lws_fi_t加入上下文(fault-injection.c)。
规则的传入时机:必须在对象创建之前
故障注入的一个关键要求是:规则必须在创建对象的代码面前可用,早于对象被创建。这就是为什么用户代码要在创建信息结构体中预先准备好故障上下文、列出规则,而不是等对象创建后再附加——那时再去测试创建期间的故障已经太迟了。
直接应用故障上下文
创建以下四类对象时,可以直接传入一个预先用lws_fi_t准备好的故障上下文:
| 被创建的对象 | 信息结构体 | 故障上下文成员 |
|---|---|---|
| lws context | struct lws_context_creation_info | fic |
| vhost | struct lws_context_creation_info | fic |
| Secure Stream | struct lws_ss_info | fic |
| 客户端 wsi | struct lws_client_connect_info | fic |
例如在 lws-context-vhost.h 中,struct lws_context_creation_info在LWS_WITH_SYS_FAULT_INJECTION条件下带有lws_fi_ctx_t fic;成员;lws-client.h 中struct lws_client_connect_info同样带有fic以及一个与构建选项无关、始终可用的fi_wsi_name成员。
不过实践中更常用的做法是:只在 context 创建时给出故障列表,让对象通过命名空间匹配并继承——这就是下一节的内容。
用命名空间精准定位实例
直接创建的 vhost、Secure Stream 或 wsi 可以在创建时直接挂接子规则,无需命名空间。命名空间用于你只握有更上层对象(如lws_context)的创建时机、而目标对象由它内部创建、你没有直接句柄的场景——例如想在某个 vhost 的监听 socket 上触发故障。
命名空间采用/path/形式,规则名可以带上前缀,使后创建的对象继承:
| 命名空间形式 | 效果 |
|---|---|
vh=myvhost/子规则 | 名为 "myvhost" 的 vhost 被创建时继承该子规则 |
vh/子规则 | 任意 vhost 被创建时继承该子规则 |
ss=mystream/子规则 | streamtype 为 "mystream" 的 SS 继承(也覆盖 SSPC / proxy 客户端) |
ss/子规则 | 任意 streamtype 的所有 SS 继承(也覆盖 SSPC / proxy 客户端) |
wsi=myname/子规则 | 以info->fi_wsi_name为 "myname" 创建的客户端 wsi 继承 |
wsi/子规则 | 任意 wsi 继承 |
命名空间可以组合。例如vh=myvhost/wsi/listenskt:在服务器 vhost "myvhost" 创建的 wsi 上设置listenskt故障,即让该 vhost 的监听 socket 在创建时报错。
值得注意的细节:h2 连接上的网络连接 wsi 被迁移为 SID 1 时(wsi migration),其上已挂接的故障也会一并迁移。
各对象的继承来源一览
| 对象类型 | 初始化的来源 | 从何处继承匹配的故障 |
|---|---|---|
| context | struct lws_context_creation_info.fic | - |
| vhost | struct lws_context_creation_info.fic | context FIC |
| 客户端 wsi | struct lws_client_connect_info.fic | context FIC, vhost FIC |
| ss / sspc | lws_ss_info_t.fic | context FIC |
| ss / sspc 的 wsi | - | context FIC, vhost FIC, ss / sspc .fic |
由于所有对象都能直接或通过逐级继承从lws_context的故障上下文触达,而从外部又最方便在 context 上设置规则,因此context 通常是所有注入故障的原始来源。
与 minimal 示例的集成:--fault-injection 与 --fault-seed
所有使用lws_cmdline_option_handle_builtin()API 的 minimal 示例都能额外接收--fault-injection "...,..."开关:该开关会自动解析参数中的逗号分隔列表,把给出的故障名加入lws_context。例如:
lws-minimal-http-client --fault-injection "wsi/dnsfail"会强制该次运行中所有 wsi 的 DNS 查询失败。
从 libwebsockets.c 可以看到,内建命令行选项数组包含-d、--fault-injection、--fault-seed、--ignore-sigterm四项;解析到--fault-injection时调用lws_fi_deserialize(&info->fic, p)把字符串解析成规则,解析到--fault-seed时把十进制字符串转为 64 位种子(libwebsockets.c)。
指定"何时"注入的语法
默认情况下,如果只给出名称部分,只要命名空间缺失或匹配到对象,故障就会每次注入。也可以用括号附加额外信息,实现随机概率或循环模式注入:
| 语法 | 配合使用 | 含义 |
|---|---|---|
wsi/thefault | lws_fi() | 每次都注入故障 |
wsi/thefault(10%) | lws_fi() | 以 10% 概率随机注入 |
wsi/thefault(.............X.X) | lws_fi() | 每 16 次尝试中,在第 14 和第 16 次注入 |
wsi/thefault2(123..456) | lws_fi_range() | 在 123 与 456 之间取一个数 |
注意:包含这些符号的字符串必须用引号包裹,否则可能被 shell 解释。pattern 中的.表示"该次不注入",X表示"该次注入"。
最后一个示例((123..456))并不像其他示例那样通过lws_fi()决定是否注入,而是配合lws_fi_range()使用,作为故障处理流程中的一个次级故障名。典型场景:先用myfault配合lws_fi()决定何时注入故障,再用第二个相关故障名myfault_delay为故障动作引入一个外部给定范围内的随机延迟(毫秒级):
"myfault(10%),myfault_delay(123..456)"代码中调用lws_fi_range()查询myfault_delay,即可拿到 123~456 之间的伪随机数,用于控制延迟等参数(见lws_fi_range()的文档注释 lws-fault-injection.h)。
lws 内置的知名故障名清单
lws 内部预置了大量可在外部直接触发的故障点,覆盖 context 创建、vhost 创建、客户端连接、UDP、Secure Streams(ss / sspc / ssproxy)等各层次:
| 范围 | 命名空间 | 名称 | 故障效果 |
|---|---|---|---|
| context | ctx_createfail1 | 进入时立即让 context 创建失败 | |
| context | ctx_createfail_plugin_init | 让 context 创建失败,如同插件初始化失败(启用插件时) | |
| context | ctx_createfail_evlib_plugin | 让 context 创建失败,如同事件库插件初始化失败(启用 evlib 插件时) | |
| context | ctx_createfail_evlib_sel | 让 context 创建失败,如同无法选择事件库 | |
| context | ctx_createfail_oom_ctx | 让 context 创建因 context 对象 OOM 而失败 | |
| context | ctx_createfail_privdrop | 让 context 创建因权限降级失败而失败 | |
| context | ctx_createfail_maxfds | 让 context 创建因无法确定进程 fd 上限而失败 | |
| context | ctx_createfail_oom_fds | 让 context 创建因 fds 表 OOM 而失败 | |
| context | ctx_createfail_plat_init | 让 context 创建因平台初始化失败而失败 | |
| context | ctx_createfail_evlib_init | 让 context 创建因事件库初始化失败而失败 | |
| context | ctx_createfail_evlib_pt | 让 context 创建因事件库 pt 初始化失败而失败 | |
| context | ctx_createfail_sys_vh | 让 context 创建因系统 vhost 创建失败而失败 | |
| context | ctx_createfail_sys_vh_init | 让 context 创建因系统 vhost 初始化失败而失败 | |
| context | ctx_createfail_def_vh | 让 context 创建因默认 vhost 创建失败而失败 | |
| context | ctx_createfail_ss_pol1 | 让 context 创建因 ss 策略解析开始失败而失败(启用策略时) | |
| context | ctx_createfail_ss_pol2 | 让 context 创建因 ss 策略解析失败而失败(启用策略时) | |
| context | ctx_createfail_ss_pol3 | 让 context 创建因 ss 策略设置失败而失败(启用策略时) | |
| context | cache_createfail | 让lws_cache创建因 OOM 失败 | |
| context | cache_lookup_oom | 让lws_cache查找因 OOM 失败 | |
| vhost | vh | vh_create_oom | vh 创建时对象分配 OOM |
| vhost | vh | vh_create_pcols_oom | vh 创建时协议表分配 OOM |
| vhost | vh | vh_create_access_log_open_fail | vh 创建因无法打开访问日志而失败(LWS_WITH_ACCESS_LOG) |
| vhost | vh | vh_create_ssl_srv | 服务端 ssl_ctx 初始化失败 |
| vhost | vh | vh_create_ssl_cli | 客户端 ssl_ctx 初始化失败 |
| vhost | vh | vh_create_srv_init | 服务器初始化失败 |
| vhost | vh | vh_create_protocol_init | 延迟协议初始化失败(用于延迟创建的 vhost) |
| 服务端 vhost | vh=xxx/wsi | listenskt | 让 vhost 监听 socket 的socket()分配失败 |
| 客户端 wsi | wsi | dnsfail | 同步:不调用getaddrinfo()并合成EAI_FAIL返回;异步:请求不启动并立即合成失败 |
| 客户端 wsi | wsi | sendfail | 在 wsi socket 上发送数据失败 |
| 客户端 wsi | wsi | connfail | 在 wsi socket 上连接失败 |
| 客户端 wsi | wsi | createfail | 创建客户端 wsi 本身失败 |
| udp wsi | wsi | udp_rx_loss | 丢弃实际收到的 UDP RX,配合概率模式使用 |
| udp wsi | wsi | udp_tx_loss | 丢弃 UDP TX 使其不被真正发送,配合概率模式使用 |
| 服务端 ss | ss | ss_srv_vh_fail | 强制 Secure Streams 服务端 vhost 创建失败 |
| 客户端 ss | ss | ss_no_streamtype_policy | 让该 streamtype 的策略看似缺失 |
| sspc | ss | sspc_fail_on_linkup | 听到代理连接成功时拒绝该连接,引发无限重试 |
| sspc | ss | sspc_fake_rxparse_disconnect_me | 让客户端-代理链路解析看似请求断开,引发无限重试 |
| sspc | ss | sspc_fake_rxparse_destroy_me | 让客户端-代理链路解析看似请求销毁 SS,将干净地销毁 SS |
| sspc | ss | sspc_link_write_fail | 强制链路写入失败,引发无限重试 |
| sspc | ss | sspc_create_oom | 让 sspc 句柄分配在创建时如同 OOM 失败 |
| sspc | ss | sspc_fail_metadata_set | 让 metadata 分配失败 |
| sspc | ss | sspc_rx_fake_destroy_me | 让客户端的用户代码rx()看似返回 DESTROY_ME |
| sspc | ss | sspc_rx_metadata_oom | 让来自代理的 metadata 分配失败 |
| ssproxy | ss | ssproxy_dsh_create_oom | 让代理的 DSH 创建失败 |
| ssproxy | ss | ssproxy_dsh_rx_queue_oom | 让 SS->P[->C] DSH rx 方向的分配如同 OOM 失败,导致后续连接断开 |
| ssproxy | wsi | ssproxy_client_adopt_oom | 让代理无法为新客户端-代理链路连接对象分配内存 |
| ssproxy | wsi | ssproxy_client_write_fail | 让代理对客户端的写入失败 |
| ssproxy | wsi | sspc_dsh_ss2p_oom | 让 ss->proxy dsh 分配失败 |
| ssproxy | ss | ssproxy_onward_conn_fail | 让代理的后续客户端连接立即失败 |
| ssproxy | ss | ssproxy_dsh_c2p_pay_oom | 让代理的 C->P payload DSH 分配失败 |
| ss | ss | ss_create_smd | SMD:ss 创建时 smd 注册失败 |
| ss | ss | ss_create_vhost | 服务端:ss 创建时看似没有匹配 typename 的 vhost(仅!vhost) |
| ss | ss | ss_create_pcol | 服务端:ss 创建时看似策略中未给出协议 |
| ss | ss | ss_srv_vh_fail | 服务端:ss 创建时看似无法创建 vhost |
| ss | ss | ss_create_destroy_me | ss 创建时看似 CREATING 状态返回了 DESTROY_ME |
| ss | ss | ss_create_no_ts | 静态策略:ss 创建时看似没有 trust store |
| ss | ss | ss_create_smd_1 | SMD:ss 创建时看似 CONNECTING 说了 DESTROY_ME |
| ss | ss | ss_create_smd_2 | SMD:ss 创建时看似 CONNECTED 说了 DESTROY_ME |
| ss | ss | ss_create_conn | Nailed up:ss 创建时客户端连接以 DESTROY_ME 失败 |
| wsi | wsi | timedclose | 让 wsi 在一段时间后关闭(配合下一个使用) |
| wsi | wsi | timedclose_ms | timedclose的毫秒范围(如"timedclose_ms(10..250)") |
这些故障名与文档、fault-injection.c 中的实现一一对应;实际触发时,lws 会在日志中打印Injecting fault告警,便于确认故障确实被注入。
已知的命名空间目标:内部 wsi 与自定义 wsi 名
命名空间可以更精准地定位目标。即便只把故障传给lws_context,也能用命名空间"路径"只针对特定来源创建的 wsi。
要定位 SS 连接产生的 wsi,可使用ss=stream_type_name/。以 captive portal 检测(CPD)为例:
ss=captive_portal_detect/ss_no_streamtype_policy # 让 CPD 找不到策略条目,从而禁用 CPD ss=captive_portal_detect/wsi/dnsfail # 让 CPD 无法解析服务器 DNS,看起来"没有网络" ss=captive_portal_detect/wsi/connfail # 针对 CPD 的连接测试部分,同样让 CPD 认为"没有网络"内部 wsi 类型名
lws 为内部功能(如异步 DNS 处理)创建的 wsi 也可以被精准定位:
| wsi 目标 | 含义 |
|---|---|
wsi=asyncdns/ | lws 异步 DNS 支持用来与 DNS 服务器通信的 UDP wsi |
wsi=dhcpc/ | lws DHCP 客户端使用的 UDP wsi |
wsi=ntpclient/ | lws NTP 客户端使用的 UDP wsi |
例如在lws_context级别传入wsi=asyncdns/udp_tx_loss,将抑制异步 DNS 的 UDP 发送,从而强制其无法解析任何域名。
对于用户自己创建的 wsi,可以在客户端连接创建时,把客户端创建信息结构体的.fi_wsi_name设置为字符串 "xxx"(lws-client.h),之后就能用wsi=xxx/命名空间只对这批 wsi 生效。minimal-http-client 中i.fi_wsi_name = "user"(minimal-http-client.c)正是为此,配合wsi/user_reject_at_est等规则即可精确命中该客户端 wsi。
小结
lws_fi 提供了一条从"构建期开启 → 创建期挂规则 → 运行时按策略触发"的完整故障注入链路:
- 构建期:以
-DLWS_WITH_SYS_FAULT_INJECTION=ON编译 lws;关闭时所有 API 退化为常量,零开销。 - 规则准备:通过
lws_fi_add()/lws_fi_deserialize()把lws_fi_t规则装入lws_fi_ctx_t,通常挂在lws_context_creation_info.fic上;对象创建时用lws_fi_import()接管,用lws_fi_inherit_copy()按vh=xxx/、ss=xxx/、wsi=xxx/命名空间向下分发。 - 触发查询:lws 私有代码用
lws_fi(),用户代码用lws_fi_user_*_fi()系列公开 API;按LWSFI_ALWAYS / DETERMINISTIC / PROBABILISTIC / PATTERN / PATTERN_ALLOC / RANGE策略决策,概率决策由 xoshiro256 PRNG 支撑,种子可通过--fault-seed固定以便复现。 - 命令行接入:minimal 示例可通过
--fault-injection "a,b,c"直接注入,(10%)、(....X.X)、(123..456)语法分别对应概率、位模式与范围取数。
配合内置的数十个知名故障点(context/vhost 创建失败、dnsfail、connfail、sendfail、udp_tx_loss、ss/sspc/ssproxy 系列),测试人员无需构造复杂的真实故障环境,即可在 CI 或本地一键复现原本低概率出现的错误路径,是验证 lws 应用健壮性的实用工具。
- 人工智能
- AI Agent
- 多模态
- 语音
- AI 应用
【免费下载链接】ten-framework
Open-source framework for conversational voice AI agents
相关推荐
SimianArmy配置详解:自定义故障注入规则与策略
SimianArmy配置详解:自定义故障注入规则与策略 项目概述 SimianArmy是一套云环境运维工具集,其中最著名的组件是Chaos Monkey(混沌猴
测试云原生LitmusChaos故障注入类型大全:网络、CPU、内存、磁盘等故障的完整解析
LitmusChaos故障注入类型大全:网络、CPU、内存、磁盘等故障的完整解析 LitmusChaos是一个强大的云原生混沌工程平台,专为Kubernetes
云原生运维可观测性突破线上故障瓶颈:JVM-SANDBOX从零构建故障注入工具实战指南
突破线上故障瓶颈:JVM SANDBOX从零构建故障注入工具实战指南 你是否还在为线上系统故障排查而头疼?是否遇到过生产环境难以复现的偶发bug?本文将带你使用
开发工具后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考