Vapor 3:如何在Job定时任务中访问Ferno服务?
在Vapor定时Job中访问Ferno服务的正确姿势
嘿,我明白你刚转Vapor后端遇到的这个困扰——在定时Job里没法调用Ferno访问Firebase确实挺挠头的。我之前也踩过类似的坑,给你捋捋正确的做法,不用绕弯子搞全局app实例或者自定义Request:
首先,别用app(.detect())!
你当前代码里的try app(.detect()).make(FernoClient.self)是个误区——app(.detect())会重新初始化整个应用实例,不仅效率极低,还会导致数据库连接池、服务配置等重复初始化,绝对不是正确的做法。
正确方案:启动时传递App实例给Job
在Vapor中,Application本身就是容器的实现,你只需要在添加Job的时候把启动好的app实例传进去就行,不用依赖控制器的弱引用。比如在configure.swift里:
func configure(_ app: Application) throws { // ... 你的其他配置(路由、数据库、Ferno等) ... // 添加定时Job时直接捕获app实例 Jobs.add(interval: (60*30).seconds) { [app] in // 从app容器中直接获取需要的服务 let fernoClient = app.make(FernoClient.self) let devicesController = app.make(DevicesController.self) // 调用检查方法,把Ferno客户端传进去 do { try devicesController.checkForNotSeenDevices(with: fernoClient) } catch { print("检查设备时出错:\(error)") } } }
修改你的检查方法,依赖注入代替全局查找
把原来的checkForNotSeenDevices改成接收FernoClient的方式,而且不需要Request——Ferno支持在后台任务中直接用事件循环调用:
func checkForNotSeenDevices(with fernoClient: FernoClient) throws { // 获取一个可用的事件循环 let eventLoop = fernoClient.application.eventLoopGroup.next() // 调用Ferno的retrieve方法,指定on参数为事件循环,不需要req fernoClient.ferno.retrieve( on: eventLoop, queryItems: [], appendedPath: ["devices"] ) .whenComplete { result in switch result { case .success(let deviceData): // 这里处理获取到的设备签到数据 print("获取到设备数据:\(deviceData)") // 你的逻辑:检查最后签到时间,处理未签到设备 case .failure(let error): print("获取设备数据失败:\(error)") } } }
关键知识点:后台任务不需要Request
Vapor的Request主要是为HTTP请求上下文设计的,而定时Job属于后台离线任务,完全不需要请求上下文。Ferno这类服务都提供了基于事件循环的调用方式,只要指定on: eventLoop就能正常工作,根本不用自定义Request。
额外提醒
- 避免用
weak引用控制器:控制器可能被提前释放,或者导致不必要的循环引用,直接从app容器中解析控制器是更可靠的方式。 - 异步操作要注意:后台任务里处理异步逻辑时,优先用
whenComplete、flatMap这类异步回调,尽量别用wait()——除非你能确保不会阻塞应用的事件循环。
内容的提问来源于stack exchange,提问作者simonthumper
相关产品推荐
相关产品推荐

