Skip to content

Move code to constraint #331

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions Sources/SwiftQueue/Constraint+Executor.swift

This file was deleted.

41 changes: 29 additions & 12 deletions Sources/SwiftQueue/Constraint+Repeat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,28 @@

import Foundation

internal final class RepeatConstraint {
internal final class RepeatConstraint: SimpleConstraint {

static func run(operation: SqOperation) -> Bool {
switch operation.info.executor {
/// Number of run maximum
internal let maxRun: Limit

/// Time between each repetition of the job
internal let interval: TimeInterval

/// Executor to run job in foreground or background
internal let executor: Executor

/// Current number of run
private var runCount: Double = 0

required init(maxRun: Limit, interval: TimeInterval, executor: Executor) {
self.maxRun = maxRun
self.interval = interval
self.executor = executor
}

override func run(operation: SqOperation) -> Bool {
switch executor {
case .background:
return false
case .foreground:
Expand All @@ -35,27 +53,26 @@ internal final class RepeatConstraint {
}
}

static func completionSuccess(sqOperation: SqOperation) {

if case .limited(let limit) = sqOperation.info.maxRun {
func completionSuccess(sqOperation: SqOperation) {
if case .limited(let limit) = maxRun {
// Reached run limit
guard sqOperation.info.runCount + 1 < limit else {
guard runCount + 1 < limit else {
sqOperation.onTerminate()
return
}
}

guard sqOperation.info.interval > 0 else {
guard interval > 0 else {
// Run immediately
sqOperation.info.runCount += 1
runCount += 1
sqOperation.run()
return
}

// Schedule run after interval
sqOperation.nextRunSchedule = Date().addingTimeInterval(sqOperation.info.interval)
sqOperation.dispatchQueue.runAfter(sqOperation.info.interval, callback: { [weak sqOperation] in
sqOperation?.info.runCount += 1
sqOperation.nextRunSchedule = Date().addingTimeInterval(interval)
sqOperation.dispatchQueue.runAfter(interval, callback: { [weak self, weak sqOperation] in
self?.runCount += 1
sqOperation?.run()
})
}
Expand Down
29 changes: 19 additions & 10 deletions Sources/SwiftQueue/Constraint+Retry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,33 @@

import Foundation

class JobRetryConstraint {
internal final class JobRetryConstraint: SimpleConstraint {

static func onCompletionFail(sqOperation: SqOperation, error: Error) {
switch sqOperation.info.retries {
/// Maximum number of authorised retried
internal var limit: Limit

required init(limit: Limit) {
self.limit = limit
}

func onCompletionFail(sqOperation: SqOperation, error: Error) {
switch limit {
case .limited(let value):
if value > 0 {
sqOperation.retryJob(retry: sqOperation.handler.onRetry(error: error), origin: error)
sqOperation.retryJob(actual: self, retry: sqOperation.handler.onRetry(error: error), origin: error)
} else {
sqOperation.onTerminate()
}
case .unlimited:
sqOperation.retryJob(retry: sqOperation.handler.onRetry(error: error), origin: error)
sqOperation.retryJob(actual: self, retry: sqOperation.handler.onRetry(error: error), origin: error)
}
}

}

fileprivate extension SqOperation {

func retryJob(retry: RetryConstraint, origin: Error) {
func retryJob(actual: JobRetryConstraint, retry: RetryConstraint, origin: Error) {

func exponentialBackoff(initial: TimeInterval) -> TimeInterval {
currentRepetition += 1
Expand All @@ -50,8 +57,8 @@ fileprivate extension SqOperation {

func retryInBackgroundAfter(_ delay: TimeInterval) {
nextRunSchedule = Date().addingTimeInterval(delay)
dispatchQueue.runAfter(delay) { [weak self] in
self?.info.retries.decreaseValue(by: 1)
dispatchQueue.runAfter(delay) { [weak actual, weak self] in
actual?.limit.decreaseValue(by: 1)
self?.run()
}
}
Expand All @@ -61,12 +68,14 @@ fileprivate extension SqOperation {
lastError = SwiftQueueError.onRetryCancel(origin)
onTerminate()
case .retry(let after):
guard after > 0 else { // Retry immediately
info.retries.decreaseValue(by: 1)
guard after > 0 else {
// Retry immediately
actual.limit.decreaseValue(by: 1)
self.run()
return
}

// Retry after time in parameter
retryInBackgroundAfter(after)
case .exponential(let initial):
retryInBackgroundAfter(exponentialBackoff(initial: initial))
Expand Down
14 changes: 12 additions & 2 deletions Sources/SwiftQueue/JobInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,21 @@ public struct JobInfo {

public var timeout: TimeInterval?

func buildConstraints() -> [JobConstraint] {
internal var repeatConstraint: RepeatConstraint? = nil
internal var retryConstraint: JobRetryConstraint? = nil

mutating func buildConstraints() -> [JobConstraint] {
var constraints = [JobConstraint]()

constraints.append(UniqueUUIDConstraint(uuid: uuid, override: override, includeExecutingJob: includeExecutingJob))
constraints.append(ExecutorConstraint())

let repeatConstraint = RepeatConstraint(maxRun: maxRun, interval: interval, executor: executor)
constraints.append(repeatConstraint)
self.repeatConstraint = repeatConstraint

let retryConstraint = JobRetryConstraint(limit: retries)
constraints.append(retryConstraint)
self.retryConstraint = retryConstraint

if requireCharging {
constraints.append(BatteryChargingConstraint())
Expand Down
14 changes: 11 additions & 3 deletions Sources/SwiftQueue/SqOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ internal final class SqOperation: Operation {
self.logger = logger
self.listener = listener
self.dispatchQueue = dispatchQueue
self.constraints = info.buildConstraints()
self.constraints = self.info.buildConstraints()

super.init()
}
Expand Down Expand Up @@ -169,15 +169,23 @@ extension SqOperation: JobResult {
logger.log(.warning, jobId: name, message: "Job completed with error \(error.localizedDescription)")
lastError = error

JobRetryConstraint.onCompletionFail(sqOperation: self, error: error)
if let constraint = info.retryConstraint {
constraint.onCompletionFail(sqOperation: self, error: error)
} else {
onTerminate()
}
}

private func completionSuccess() {
logger.log(.verbose, jobId: name, message: "Job completed successfully")
lastError = nil
currentRepetition = 0

RepeatConstraint.completionSuccess(sqOperation: self)
if let constraint = info.repeatConstraint {
constraint.completionSuccess(sqOperation: self)
} else {
onTerminate()
}
}

}
Expand Down
4 changes: 3 additions & 1 deletion Sources/ios/SwiftQueueManager+BackgroundTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public extension SwiftQueueManager {
/// Cancel all possible background Task
func cancelAllBackgroundTask() {
for operation in getAllAllowBackgroundOperation() {
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: operation.info.uuid)
if let uuid = operation.name {
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: uuid)
}
}
}
}
Expand Down
10 changes: 0 additions & 10 deletions SwiftQueue.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@
61A65B7822ABD175009AC9B7 /* Constraint+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A65B7622ABD172009AC9B7 /* Constraint+Timeout.swift */; };
61A65B7922ABD175009AC9B7 /* Constraint+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A65B7622ABD172009AC9B7 /* Constraint+Timeout.swift */; };
61A65B7A22ABD176009AC9B7 /* Constraint+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61A65B7622ABD172009AC9B7 /* Constraint+Timeout.swift */; };
61F41E27231BDD08001A4B62 /* Constraint+Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F41E26231BDD08001A4B62 /* Constraint+Executor.swift */; };
61F41E28231BDD08001A4B62 /* Constraint+Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F41E26231BDD08001A4B62 /* Constraint+Executor.swift */; };
61F41E29231BDD08001A4B62 /* Constraint+Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F41E26231BDD08001A4B62 /* Constraint+Executor.swift */; };
61F41E2A231BDD08001A4B62 /* Constraint+Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F41E26231BDD08001A4B62 /* Constraint+Executor.swift */; };
95A210264F99EAC94629D786 /* SwiftQueueLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A217FDB8197696002CE25C /* SwiftQueueLogger.swift */; };
95A213CFEA10D6FD5672A64A /* JobInfoSerializer+V1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A210DDE517DF37DE5A7EC1 /* JobInfoSerializer+V1.swift */; };
95A2142AD4929198F8C2534D /* Constraint+Charging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A21C01EDB773B7F17134AF /* Constraint+Charging.swift */; };
Expand Down Expand Up @@ -155,7 +151,6 @@
1E68EF96F1DE038FFF94FCD8 /* Constraint+Deadline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Constraint+Deadline.swift"; path = "SwiftQueue/Constraint+Deadline.swift"; sourceTree = "<group>"; };
618E9CE2230E1F1000856158 /* SwiftQueueManager+BackgroundTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "SwiftQueueManager+BackgroundTask.swift"; path = "ios/SwiftQueueManager+BackgroundTask.swift"; sourceTree = "<group>"; };
61A65B7622ABD172009AC9B7 /* Constraint+Timeout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Constraint+Timeout.swift"; path = "SwiftQueue/Constraint+Timeout.swift"; sourceTree = "<group>"; };
61F41E26231BDD08001A4B62 /* Constraint+Executor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Constraint+Executor.swift"; path = "SwiftQueue/Constraint+Executor.swift"; sourceTree = "<group>"; };
95A210DDE517DF37DE5A7EC1 /* JobInfoSerializer+V1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "JobInfoSerializer+V1.swift"; path = "SwiftQueue/JobInfoSerializer+V1.swift"; sourceTree = "<group>"; };
95A2169E6968B5F155D5B612 /* JobInfoSerializer+Decodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "JobInfoSerializer+Decodable.swift"; path = "SwiftQueue/JobInfoSerializer+Decodable.swift"; sourceTree = "<group>"; };
95A217FDB8197696002CE25C /* SwiftQueueLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftQueueLogger.swift; path = SwiftQueue/SwiftQueueLogger.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -288,7 +283,6 @@
OBJ_7 /* Sources */ = {
isa = PBXGroup;
children = (
61F41E26231BDD08001A4B62 /* Constraint+Executor.swift */,
618E9CE2230E1F1000856158 /* SwiftQueueManager+BackgroundTask.swift */,
61A65B7622ABD172009AC9B7 /* Constraint+Timeout.swift */,
1D8479A61F82A84B00B3BBFB /* Constraint.swift */,
Expand Down Expand Up @@ -473,7 +467,6 @@
D0B7C8729FA2F6EF3A6C42F8 /* JobBuilder.swift in Sources */,
D0B7C9AE1E4717DE474FD804 /* SqOperationQueue.swift in Sources */,
95A21FA05AABFA4A59096E8E /* SwiftQueueLogger.swift in Sources */,
61F41E28231BDD08001A4B62 /* Constraint+Executor.swift in Sources */,
95A21FA0723161F6908B133B /* Constraint+Charging.swift in Sources */,
618E9CE4230E1F1300856158 /* SwiftQueueManager+BackgroundTask.swift in Sources */,
95A21B7D3F013BAF87216CF0 /* JobInfoSerializer+Decodable.swift in Sources */,
Expand All @@ -487,7 +480,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 0;
files = (
61F41E29231BDD08001A4B62 /* Constraint+Executor.swift in Sources */,
B06405121FA04AAC00086C69 /* UserDefaultsPersister.swift in Sources */,
B06405131FA04AAC00086C69 /* SwiftQueue.swift in Sources */,
61A65B7922ABD175009AC9B7 /* Constraint+Timeout.swift in Sources */,
Expand Down Expand Up @@ -515,7 +507,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 0;
files = (
61F41E2A231BDD08001A4B62 /* Constraint+Executor.swift in Sources */,
B06405211FA04CCF00086C69 /* UserDefaultsPersister.swift in Sources */,
B06405221FA04CCF00086C69 /* SwiftQueue.swift in Sources */,
61A65B7822ABD175009AC9B7 /* Constraint+Timeout.swift in Sources */,
Expand Down Expand Up @@ -544,7 +535,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 0;
files = (
61F41E27231BDD08001A4B62 /* Constraint+Executor.swift in Sources */,
1D8479A81F82A84B00B3BBFB /* UserDefaultsPersister.swift in Sources */,
1D8479A91F82A84B00B3BBFB /* SwiftQueue.swift in Sources */,
61A65B7722ABD172009AC9B7 /* Constraint+Timeout.swift in Sources */,
Expand Down