Skip to content

Commit 4fa1ef9

Browse files
authored
Add every(interval) feature (#146)
* Add every(interval) feature * Make the test queue driver error instead of crashing
1 parent 1f9c136 commit 4fa1ef9

3 files changed

Lines changed: 63 additions & 4 deletions

File tree

Sources/Queues/ScheduleBuilder.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ public final class ScheduleBuilder: @unchecked Sendable {
182182

183183
/// Retrieves the next date after the one given.
184184
public func nextDate(current: Date = .init()) -> Date? {
185+
if let interval = self.interval { return current.addingTimeInterval(interval) }
185186
if let date = self.date, date > current { return date }
186187

187188
var components = DateComponents()
@@ -202,11 +203,12 @@ public final class ScheduleBuilder: @unchecked Sendable {
202203

203204
/// The calendar used to compute the next date
204205
var calendar: Calendar
205-
206+
206207
/// Date to perform task (one-off job)
207208
var date: Date?
208209
var month: Month?, day: Day?, weekday: Weekday?
209210
var time: Time?, minute: Minute?, second: Second?, millisecond: Int?
211+
var interval: TimeInterval?
210212

211213
public init(calendar: Calendar = .current) { self.calendar = calendar }
212214

@@ -236,4 +238,19 @@ public final class ScheduleBuilder: @unchecked Sendable {
236238

237239
/// Runs a job every second
238240
public func everySecond() { self.millisecond = 0 }
241+
242+
/// Runs a job every given number of seconds
243+
public func every(seconds: Int) { self.interval = TimeInterval(seconds) }
244+
245+
/// Runs a job every given number of minutes
246+
public func every(minutes: Int) { self.interval = TimeInterval(minutes * 60) }
247+
248+
/// Runs a job every given number of hours
249+
public func every(hours: Int) { self.interval = TimeInterval(hours * 3_600) }
250+
251+
/// Runs a job every given number of days
252+
public func every(days: Int) { self.interval = TimeInterval(days * 86_400) }
253+
254+
/// Runs a job every given number of weeks
255+
public func every(weeks: Int) { self.interval = TimeInterval(weeks * 604_800) }
239256
}

Sources/XCTQueues/TestQueueDriver.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,18 @@ extension Application.Queues {
114114
}
115115
}
116116

117+
struct NoSuchJobError: Error { let id: JobIdentifier }
118+
117119
struct TestQueue: Queue {
118120
let _context: NIOLockedValueBox<QueueContext>
119121
var context: QueueContext { self._context.withLockedValue { $0 } }
120122

121123
func get(_ id: JobIdentifier) -> EventLoopFuture<JobData> {
122124
self._context.withLockedValue { context in
123-
context.eventLoop.makeSucceededFuture(context.application.queues.test.jobs[id]!)
125+
guard let job = context.application.queues.test.jobs[id] else {
126+
return context.eventLoop.makeFailedFuture(NoSuchJobError(id: id))
127+
}
128+
return context.eventLoop.makeSucceededFuture(job)
124129
}
125130
}
126131

@@ -156,7 +161,7 @@ struct AsyncTestQueue: AsyncQueue {
156161
let _context: NIOLockedValueBox<QueueContext>
157162
var context: QueueContext { self._context.withLockedValue { $0 } }
158163

159-
func get(_ id: JobIdentifier) async throws -> JobData { self._context.withLockedValue { $0.application.queues.asyncTest.jobs[id]! } }
164+
func get(_ id: JobIdentifier) async throws -> JobData { try self._context.withLockedValue { guard let job = $0.application.queues.asyncTest.jobs[id] else { throw NoSuchJobError(id: id) }; return job } }
160165
func set(_ id: JobIdentifier, to data: JobData) async throws { self._context.withLockedValue { $0.application.queues.asyncTest.jobs[id] = data } }
161166
func clear(_ id: JobIdentifier) async throws { self._context.withLockedValue { $0.application.queues.asyncTest.jobs[id] = nil } }
162167
func pop() async throws -> JobIdentifier? { self._context.withLockedValue { $0.application.queues.asyncTest.popFirst() } }

Tests/QueuesTests/ScheduleBuilderTests.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,44 @@ final class ScheduleBuilderTests: XCTestCase {
138138
Date(year: 2020, month: 5, day: 23, hour: 14, minute: 58)
139139
)
140140
}
141-
141+
142+
func testEveryWeeksBuilder() throws {
143+
let builder = ScheduleBuilder()
144+
builder.every(weeks: 3)
145+
let now = Date(hour: 5, minute: 0)
146+
XCTAssertEqual(builder.nextDate(current: now), Date(day: 22, hour: 5))
147+
}
148+
149+
func testEveryDaysBuilder() throws {
150+
let builder = ScheduleBuilder()
151+
builder.every(days: 9)
152+
let now = Date(hour: 5, minute: 0)
153+
XCTAssertEqual(builder.nextDate(current: now), Date(day: 10, hour: 5))
154+
}
155+
156+
func testEveryMinutesBuilder() throws {
157+
let builder = ScheduleBuilder()
158+
builder.every(minutes: 30)
159+
let now = Date(hour: 5, minute: 0)
160+
XCTAssertEqual(builder.nextDate(current: now), Date(hour: 5, minute: 30))
161+
XCTAssertEqual(builder.nextDate(current: Date(hour: 5, minute: 30)), Date(hour: 6, minute: 0))
162+
}
163+
164+
func testEveryHoursBuilder() throws {
165+
let builder = ScheduleBuilder()
166+
builder.every(hours: 5)
167+
let now = Date(hour: 0, minute: 0)
168+
XCTAssertEqual(builder.nextDate(current: now), Date(hour: 5, minute: 0))
169+
XCTAssertEqual(builder.nextDate(current: Date(hour: 5, minute: 0)), Date(hour: 10, minute: 0))
170+
}
171+
172+
func testEverySecondsBuilder() throws {
173+
let builder = ScheduleBuilder()
174+
builder.every(seconds: 90)
175+
let now = Date(hour: 1, minute: 0, second: 0)
176+
XCTAssertEqual(builder.nextDate(current: now), Date(hour: 1, minute: 1, second: 30))
177+
}
178+
142179
func testCustomCalendarBuilder() throws {
143180
let est = Calendar.calendar(timezone: "EST")
144181
let mst = Calendar.calendar(timezone: "MST")

0 commit comments

Comments
 (0)