revel.controller.reuse=true必须显式开启,否则即使配置stack和maxstack,对象池也不生效;cache默认为进程内内存,不跨实例;静态资源版本号需通过拦截器注入模板;Job缓存更新须forget+set配对。

revel.controller.reuse=true 必须显式开启
Revel 默认不启用控制器对象复用,哪怕你配置了 revel.controller.stack,revel.controller.maxstack 也只在复用开启后才生效。不设 revel.controller.reuse=true,每个请求仍会新建控制器实例,对象池形同虚设。
这个开关必须写在 app.conf 里,且需在应用启动前加载:
revel.controller.reuse = true revel.controller.stack = 20 revel.controller.maxstack = 500
- 值为
false或未声明,等于没开 - 修改后需重启服务,热重载不触发 controller pool 重建
- 若用 Docker,确保
app.conf被正确挂载,别被镜像内默认配置覆盖
cache.Get / cache.Set 的默认存储是进程内内存
Revel 自带的 github.com/robfig/revel/cache 包,底层默认使用 memory 驱动——也就是 Go 的 sync.Map,数据仅存于当前实例内存中,不跨进程、不跨机器。
这意味着:
- 单机部署时可用,但扩容到多实例后缓存无法共享,
cache.Get可能返回空或旧值 - 不支持 TTL 自动过期,依赖你传入的
time.Duration做手动判断(实际是靠后台 goroutine 定期扫描清理) - 若要分布式一致,必须切换驱动:改用
memcached或redis,并在app.conf中配置cache.implementation = "redis"和连接参数
示例键值操作:
err := cache.Get("user_123", &user)
if err != nil {
user = db.FindUser(123)
cache.Set("user_123", user, time.Minute*10)
}
静态资源版本号注入得靠拦截器+模板变量
Revel 没有内置 asset fingerprinting,浏览器强缓存 CSS/JS 导致更新不生效,不能靠改文件名或构建脚本硬编码,得走框架层可控路径。
核心是把版本标识(如 Git commit SHA)从配置注入到所有模板上下文,再由模板拼进 URL:
- 拦截器里读
revel.Config.StringDefault("resourceVersion", "1"),赋给c.RenderArgs["resourceVersion"] - 模板中统一写成
<link rel="stylesheet" href="/public/css/app.css?v=%7B%7B.resourceVersion%7D%7D"> -
app.conf中每次发布前更新resourceVersion = "abc789def",无需改代码或模板
注意:resourceVersion 若含斜杠、空格等非法 URL 字符,浏览器会拒绝请求——务必用纯字母数字或短横线。
Job 定时任务的缓存更新必须配对 forget + set
用 jobs.Schedule("@every 5m", &updateHotPostsJob) 刷缓存时,只 cache.Set() 不够。如果上游数据源被外部脚本、SQL 直连或队列任务修改,缓存就彻底脏了。
安全做法是「先删后写」:
- 在 Job 的
Run()开头加cache.Forget("hot_posts_list") - 再查库、处理、
cache.Set("hot_posts_list", data, time.Hour) - 避免用
cache.Get()判断存在再更新——竞态下可能刚判断完就被别人改了
更关键的是:Job 运行失败时,cache.Forget() 已执行但 Set() 没走,会导致后续请求击穿缓存直连 DB。建议加简单重试或 fallback 日志告警。
真正卡住性能的往往不是缓存有没有,而是对象生命周期、缓存作用域、失效时机这三处边界是否对齐。比如 controller 复用开了但没压测验证 GC 行为,或 resourceVersion 拼错导致全站静态资源 404,这些细节比选 Redis 还要命。



















