如何解决基于 Swift 服务器计时器的线程在 AWS 上重新部署 Docker 容器后仍然存在
在我的基于 Swift 语言的服务器的临时设计中,它由两个主要部分组成:
-
一个请求处理部分,它只处理服务器 API 的 HTTP 请求。对于服务器来说,这一切照旧。
-
一个基于计时器的线程,它会定期唤醒并处理某些类型的请求已创建的任务。这些任务位于服务器的两个部分都可以访问的数据库表中。
服务器的这两部分位于同一个 Docker 容器中,并在 AWS Elastic Beanstalk 上运行。我关心的是第二个基于计时器的部分。
它使用以下计时器:
// Adapted from https://gist.github.com/danielgalasko/1da90276f23ea24cb3467c33d2c05768
import Foundation
import LoggerAPI
/// RepeatingTimer mimics the API of dispatchSourceTimer but in a way that prevents
/// crashes that occur from calling resume multiple times on a timer that is
/// already resumed (noted by https://github.com/SiftScience/sift-ios/issues/52
class RepeatingTimer {
let timeInterval: TimeInterval
init(timeInterval: TimeInterval) {
self.timeInterval = timeInterval
}
private lazy var timer: dispatchSourceTimer = {
let t = dispatchSource.makeTimerSource()
t.schedule(deadline: .Now() + .seconds(Int(self.timeInterval)),repeating: .seconds(Int(self.timeInterval)))
t.setEventHandler(handler: { [weak self] in
self?.eventHandler?()
})
return t
}()
var eventHandler: (() -> Void)?
private enum State {
case suspended
case resumed
}
private var state: State = .suspended
deinit {
Log.debug("RepeatingTimer: deinit")
eventHandler = nil
timer.setEventHandler {}
timer.cancel()
/*
If the timer is suspended,calling cancel without resuming
triggers a crash. This is documented here https://forums.developer.apple.com/thread/15902
*/
resume()
}
func resume() {
if state == .resumed {
return
}
state = .resumed
timer.resume()
}
func suspend() {
if state == .suspended {
return
}
state = .suspended
timer.suspend()
}
}
在服务器启动时调用,如下所示:
repeatingTimer = RepeatingTimer(timeInterval: interval)
repeatingTimer?.eventHandler = { [weak self] in
guard let self = self else { return }
Log.debug("PeriodicUploader: About to run Uploader")
self.uploader = Uploader(services: self.services,delegate: nil)
do {
try self.uploader.run()
} catch let error {
Log.error("\(error)")
}
self.schedule()
}
repeatingTimer?.resume()
奇怪的是,当我部署一个新的服务器版本(一个新的 Docker 容器)时,我发现至少在某些情况下,服务器的基于计时器的部分不会关闭。我采取了一些服务器端步骤 (https://github.com/SyncServerII/ServerMain/issues/14),在新部署上彻底/完全重启服务器实例来解决这个问题,但我仍然很好奇。看起来这些预定的计时器实例不应该在 Docker 容器更换后继续存在。
我的猜测是,我正在使用的计时器必须以某种方式有效地保持对正在运行的代码的引用,并且即使在新的 Docker 容器部署中,该引用和也会保留。
[对于那些可能会问的人:为什么要以这种方式使用计时器?我不打算长期这样做。我计划将服务器的第二部分转移到 AWS Lambda 之类的地方,但还没有这样做]。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。