diff --git a/SwiftTask/SwiftTask.swift b/SwiftTask/SwiftTask.swift index 7fec21b..5008326 100644 --- a/SwiftTask/SwiftTask.swift +++ b/SwiftTask/SwiftTask.swift @@ -185,6 +185,14 @@ public class Task: Cancellable, CustomStringConvertible }) self.name = "RejectedTask" } + + private convenience init(_errorInfo: ErrorInfo) + { + self.init(_initClosure: { _, progress, fulfill, _reject, configure in + _reject(_errorInfo) + }) + self.name = "RejectedTask" + } /// /// Create promise-like task which only allows fulfill & reject (no progress & configure) @@ -310,18 +318,24 @@ public class Task: Cancellable, CustomStringConvertible clonedTask.name = "\(self.name)-clone" return clonedTask } - + /// Returns new task that is retryable for `maxRetryCount (= maxTryCount-1)` times. - public func retry(maxRetryCount: Int) -> Task + /// - Parameter condition: Predicate that will be evaluated on each retry timing. + public func retry(maxRetryCount: Int, condition: (ErrorInfo -> Bool) = { _ in true }) -> Task { - if maxRetryCount < 1 { return self } - + guard maxRetryCount > 0 else { return self } + return Task { machine, progress, fulfill, _reject, configure in let task = self.progress { _, progressValue in progress(progressValue) - }.failure { [unowned self] _ -> Task in - return self.clone().retry(maxRetryCount-1) // clone & try recursively + }.failure { [unowned self] errorInfo -> Task in + if condition(errorInfo) { + return self.clone().retry(maxRetryCount-1, condition: condition) // clone & try recursively + } + else { + return Task(_errorInfo: errorInfo) + } } task.progress { _, progressValue in diff --git a/SwiftTaskTests/SwiftTaskTests.swift b/SwiftTaskTests/SwiftTaskTests.swift index b7fedd6..f88e753 100644 --- a/SwiftTaskTests/SwiftTaskTests.swift +++ b/SwiftTaskTests/SwiftTaskTests.swift @@ -892,6 +892,41 @@ class SwiftTaskTests: _TestCase XCTAssertEqual(actualTryCount, maxTryCount, "`actualTryCount` should reach `maxTryCount` because task keeps rejected and never fulfilled.") } + func testRetry_condition() + { + // NOTE: this is async test + if !self.isAsync { return } + + let expect = self.expectationWithDescription(#function) + let maxTryCount = 4 + var actualTryCount = 0 + + Task { progress, fulfill, reject, configure in + + self.perform { + actualTryCount += 1 + reject("ERROR \(actualTryCount)") + } + + }.retry(maxTryCount-1) { error, isCancelled -> Bool in + XCTAssertNotEqual(error!, "ERROR 0", "Should not evaluate retry condition on first try. It is not retry.") + return actualTryCount < 3 + }.failure { error, isCancelled -> String in + + XCTAssertEqual(error!, "ERROR 3") + XCTAssertFalse(isCancelled) + + expect.fulfill() + + return "DUMMY" + + } + + self.wait() + + XCTAssertEqual(actualTryCount, 3) + } + func testRetry_progress() { // NOTE: this is async test