微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

基于 Swift 服务器计时器的线程在 AWS 上重新部署 Docker 容器后仍然存在

如何解决基于 Swift 服务器计时器的线程在 AWS 上重新部署 Docker 容器后仍然存在

在我的基于 Swift 语言的服务器的临时设计中,它由两个主要部分组成:

  1. 一个请求处理部分,它只处理服务器 API 的 HTTP 请求。对于服务器来说,这一切照旧。

  2. 一个基于计时器的线程,它会定期唤醒并处理某些类型的请求已创建的任务。这些任务位于服务器的两个部分都可以访问的数据库表中。

服务器的这两部分位于同一个 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?