defer 与命名返回值在错误包装时的执行顺序陷阱
线上排查一个 Go 服务的错误日志时,发现所有经过 defer 包装的错误,errors.Is 全都返回 false,日志里的 %+v 也看不到原始堆栈。代码长这样: func LoadConfig(path string) (cfg *Config, err error) { defer func() { if err != nil { err = fmt
FWDD.NET · 技术文档站
聚焦后端工程实践:语言教程、功能实现、面试题与运维脚本。每篇都从真实踩坑场景出发,给出可直接复用的代码与取舍依据。
线上排查一个 Go 服务的错误日志时,发现所有经过 defer 包装的错误,errors.Is 全都返回 false,日志里的 %+v 也看不到原始堆栈。代码长这样: func LoadConfig(path string) (cfg *Config, err error) { defer func() { if err != nil { err = fmt
在 Nginx 里做反向代理,最容易踩的坑之一,就是 location 前缀和 proxy_pass 尾部斜杠的搭配。表现往往是:本地用 curl 直连后端 200,经过 Nginx 就变成 404;或者用 /api/health 探活一直 404,但日志里看不出任何"配置错误"——因为 Nginx 认为一切正常,它只是把你请求的 URI 按规则改写后转发出
用 paramiko 对几十上百台机器批量跑命令,最容易踩的两个坑是:远端命令卡住导致线程永久阻塞,以及stderr 没读干净导致 exit_status 拿到 None。前者会让整个批量任务的时间不可控,后者会让你明明看到失败却拿不到错误原因。paramiko 本身没有内置的命令级超时,exec_command 的 timeout 参数只作用于 chann
写表单状态、配置对象、API 返回数据这些类型时,几乎每个人都遇到过同一类麻烦:上游类型把字段标成了 readonly,下游需要可写副本;上游把字段标成可选 ?,下游需要一份字段齐全的完整对象。手写一个新 interface 能解决,但字段一多就会和上游脱节——上游加字段,下游忘了同步,编译不报错,运行时才炸。TypeScript 的映射类型(mapped
面试里问 Promise,最常见的翻车点不是 new Promise 怎么写,而是被问到「上一个 then 里 return 了个东西 / throw 了个错,下一个 then 到底走 onFulfilled 还是 onRejected」时开始含糊。这个问题之所以容易答错,是因为它同时牵扯三件事:then 的返回值如何被 Promise.resolve 包装
很多团队改 /etc/ssh/sshd_config 的方式还是「登上去 vim 一下,然后 systemctl reload sshd」。这种做法的风险不在于改错一两行,而在于改完之后没人知道这台机器上到底改过什么:三年前有人把 PermitRootLogin 改成 yes,两年半前另一个人把 PasswordAuthentication 复制了两行、一行
购物车是电商系统里最容易出现并发写冲突的数据结构之一:同一个用户可能在 App、小程序、Web 三端同时操作,也可能因为网络重试导致同一个「加购 +1」请求被提交两次。如果直接对 Redis Hash 里的 quantity 字段做 HINCRBY,数字本身不会写坏,但业务规则会被绕过——比如「单 SKU 最多 99 件」的限购、「购物车最多 50 个 SK
写业务代码时经常遇到这种场景:一个 List 里装着一批订单或用户对象,要先按主字段排序,主字段相等再按次字段排序,而某些字段本身允许为 null。直接写 Comparator.comparing(Order::getAmount).thenComparing(Order::getCreateTime),一旦遇到 null 字段就会在读数据时抛 NullPo
线上一条订单落库接口偶发 Lock wait timeout exceeded; try restarting transaction,日志里死锁检测输出 insert intention lock 与 gap lock 互相等待。开发同学第一反应是"我插的是新数据,没人锁它"。这正是间隙锁最常见的认知盲区:间隙锁锁的是范围,而 INSERT 需要的插入意向