SwiftQ

MIT License Swift 4.0

SwiftQ

它是什么?

SwiftQ 是一个用于服务器端 Swift 应用程序的分布式任务队列。 任务队列被用作一种在机器之间分配工作负载的机制。 SwiftQ 使用消息在客户端和工作进程之间进行通信。 在这种情况下,消息代理是 Redis。 SwiftQ 使用 可靠队列模式。 这确保了即使在发生网络问题或消费者崩溃的情况下,所有任务都能得到处理。 SwiftQ 可用于实时操作以及任务的延迟执行。 SwiftQ 可以由多个生产者和消费者组成,从而实现高可用性和水平扩展。

用途

SwiftQ 用于在通常的 HTTP 请求-响应周期之外执行任务。 示例如下:

特性

配置

Redis 配置

建议使用单独的 Redis 数据库以避免冲突的命名空间。

let redisConfig = RedisConfig(redisDB: 0, hostname: "127.0.0.1", port: 6379, password: nil)
let configuration = Configuration(pollingInterval: 1000, 
                                  enableScheduling: true,
                                  concurrency: 4,
                                  redisConfig: .development,
                                  tasks: [EmailTask.self])

为了便于开发,RedisConfig 具有一个静态变量 development,它返回一个具有默认主机名和端口的 RedisConfig。 pollingInterval 是 SwiftQ 轮询计划队列的间隔(以毫秒为单位)。 可以将 enableScheduling 设置为 false,以便禁用使用者轮询计划队列。 请注意,轮询仅用于监视使用 Redis 的 Sorted Set 类型的计划队列。 对于所有其他任务,Redis 的 BRPOPLPUSH 命令用于确定何时可以执行任务。 所有任务都必须注册,SwiftQ 才能处理它们。

用法

生产者

定义一个生产者并将任务推送到任务队列中。

let producer = try SwiftQProducer(redisConfig: .development)
let demoTask = DemoTask()
try producer.enqueue(demoTask)

消费者

创建一个消费者。 一旦消费者启动,它将开始处理任务。 必须使用要消费的任务类型初始化消费者。

let consumer = try SwiftQConsumer(configuration)
consumer.start()

请注意,单个应用程序既可以是消费者也可以是生产者,这可能使部署比拥有专用于作为消费者的机器更容易。

创建任务

每个任务都必须符合 Task 协议。 storage 属性允许 SwiftQ 在您的模型上存储额外的信息,例如 id、执行尝试次数等。 任务自动符合 Codable。 如果需要提供自定义编码逻辑,请在您的任务中包含 func encode(to encoder: Encoder) throws

final class EmailTask: Task {
    
    let storage: Storage
    let email: String
    
    init(email: String) {
        self.storage = Storage(EmailTask.self)
        self.email = email
    }
    
    func execute() throws {
        
    }
}

调度任务

调度对于发送后续电子邮件或发送提醒等事情非常方便。 任何任务都可以被调度。

try producer.enqueue(task: demo, time: .seconds(30))

此任务将在 30 秒后运行。

注意:该任务不会完全在提供的时间触发。 相反,一旦该时间过去,该任务将从计划队列移动到工作队列,并将随着工作人员空闲下来处理它而完成。

定期任务

定期任务有很多用途。 例如,Web 应用程序可以每 10 分钟轮询一次 API 以收集数据。 SwiftQ 将处理调用代码以调用 API、处理结果并将结果存储在持久数据库中,以供客户端稍后使用。

final class PollTask: PeriodicTask {
    
    let storage: Storage
    let url: String
    
    init(url: String) {
        self.storage = Storage(PollTask.self)
        self.url = url
    }
    
    func execute() throws {
        // Make request
    }
    
    var frequency: PeriodicTime {
        return .daily(minute: 30, hour: 5)
    }
}

此任务将在每天凌晨 5:30 运行。 定期任务必须符合 PeriodicTask 协议。

高级用法

默认情况下,所有使用者都从同一个队列中消费任务。 您可能希望指定一个自定义队列,只有某些任务被路由到该队列。 为此,只需将其添加到您的任务中

var queue: String {
    return "custom"
}

您还需要在消费者配置中指定自定义队列。

注意:消费者只能从一个队列中消费。

支持的类型

SwiftQ 在将任务发送到代理之前将其编码为 JSON。 因此,只能支持具有本机 JSON 表示形式的类型。 支持的类型有

JSON 格式

{
  "storage" : {
    "retryCount" : 0,
    "taskType" : "task",
    "name" : "EmailTask",
    "enqueuedAt" : 1507815271,
    "uuid" : "90872C7C-FCC8-4130-9872-87C619489664"
  },
  "email" : "example@example.com"
}

安装

使用以下内容更新您的 Package.swift 文件

.Package(url: "https://github.com/John-Connolly/SwiftQ.git", majorVersion: 0)