Skip to content

Commit

Permalink
fix Scheduler tests
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuawright11 committed Jul 27, 2024
1 parent e78ec9c commit e9db94e
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 53 deletions.
4 changes: 4 additions & 0 deletions Alchemy/Queue/Queue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ public final class Queue: IdentifiedService {
/// The default channel to dispatch jobs on for all queues.
public static var defaultChannel = "default"

/// The number of workers on this queue.
public var workers: Int

/// The provider backing this queue.
private let provider: QueueProvider

/// Initialize a queue backed by the given provider.
public init(provider: QueueProvider) {
self.provider = provider
self.workers = 0
}

/// Enqueues a generic `Job` to this queue on the given channel.
Expand Down
1 change: 1 addition & 0 deletions Alchemy/Queue/QueueWorker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ extension Queue {
public func startWorker(for channels: [String] = [Queue.defaultChannel],
pollRate: Duration = .seconds(1),
untilEmpty: Bool = true) {
workers += 1
Life.addService(
QueueWorker(
queue: self,
Expand Down
2 changes: 1 addition & 1 deletion Alchemy/Scheduler/Commands/ScheduleCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ struct ScheduleCommand: Command {

func run() async throws {
Schedule.start()
try await gracefulShutdown()
try await Life.runServices()
}
}
5 changes: 1 addition & 4 deletions Alchemy/Scheduler/Frequency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,7 @@ public final class Frequency: AsyncSequence {
let frequency: Frequency

public mutating func next() async throws -> Foundation.Date? {
guard let delay = frequency.timeUntilNext() else {
return nil
}

guard let delay = frequency.timeUntilNext() else { return nil }
try await Task.sleep(for: delay)
return Date()
}
Expand Down
6 changes: 4 additions & 2 deletions Alchemy/Scheduler/Scheduler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ServiceLifecycle
/// A service for scheduling recurring work, in lieu of a separate cron task
/// running apart from your server.
public final class Scheduler {
private struct Task: Service, @unchecked Sendable {
struct Task: Service, @unchecked Sendable {
let name: String
let frequency: Frequency
let task: () async throws -> Void
Expand All @@ -29,10 +29,12 @@ public final class Scheduler {
}
}

private var tasks: [Task] = []
var isStarted = false
var tasks: [Task] = []

/// Start scheduling.
public func start() {
isStarted = true
Log.info("Scheduling \(tasks.count) tasks.")
for task in tasks {
Life.addService(task)
Expand Down
6 changes: 4 additions & 2 deletions Tests/HTTP/Commands/ServeCommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ final class ServeCommandTests: TestCase<TestApp> {
}

func testServe() async throws {
let exp = expectation(description: "")
Schedule.task { exp.fulfill() }.everySecond()
app.get("/foo", use: { _ in "hello" })
app.background("--port", "3000")
try await Http.get("http://127.0.0.1:3000/foo")
.assertBody("hello")

XCTAssertEqual(Q.workers.count, 0)
XCTAssertEqual(Q.workers, 0)
XCTAssertFalse(Schedule.isStarted)
}

Expand All @@ -25,7 +27,7 @@ final class ServeCommandTests: TestCase<TestApp> {
try await Http.get("http://127.0.0.1:3000/foo")
.assertBody("hello")

XCTAssertEqual(Q.workers.count, 2)
XCTAssertEqual(Q.workers, 2)
XCTAssertTrue(Schedule.isStarted)
}
}
8 changes: 4 additions & 4 deletions Tests/Queues/Commands/WorkCommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class WorkCommandTests: TestCase<TestApp> {
// wait for services to boot up
try await Task.sleep(for: .milliseconds(10))

XCTAssertEqual(Q.workers.count, 5)
XCTAssertEqual(Q.workers, 5)
XCTAssertFalse(Schedule.isStarted)
}

Expand All @@ -25,8 +25,8 @@ final class WorkCommandTests: TestCase<TestApp> {
// wait for services to boot up
try await Task.sleep(for: .milliseconds(10))

XCTAssertEqual(Q.workers.count, 0)
XCTAssertEqual(Q("a").workers.count, 5)
XCTAssertEqual(Q.workers, 0)
XCTAssertEqual(Q("a").workers, 5)
XCTAssertFalse(Schedule.isStarted)
}

Expand All @@ -36,7 +36,7 @@ final class WorkCommandTests: TestCase<TestApp> {
// wait for services to boot up
try await Task.sleep(for: .milliseconds(10))

XCTAssertEqual(Q.workers.count, 3)
XCTAssertEqual(Q.workers, 3)
XCTAssertTrue(Schedule.isStarted)
}
}
6 changes: 3 additions & 3 deletions Tests/Queues/QueueTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ final class QueueTests: TestCase<TestApp> {
try await ConfirmableJob().dispatch()

let loop = EmbeddedEventLoop()
Q.startWorker(on: loop)
Q.startWorker()
loop.advanceTime(by: .seconds(5))

await fulfillment(of: [exp], timeout: kMinTimeout)
Expand All @@ -96,7 +96,7 @@ final class QueueTests: TestCase<TestApp> {
try await FailureJob().dispatch()

let loop = EmbeddedEventLoop()
Q.startWorker(on: loop)
Q.startWorker()
loop.advanceTime(by: .seconds(5))

await fulfillment(of: [exp], timeout: kMinTimeout)
Expand All @@ -109,7 +109,7 @@ final class QueueTests: TestCase<TestApp> {
try await RetryJob(foo: "bar").dispatch()

let loop = EmbeddedEventLoop()
Q.startWorker(untilEmpty: false, on: loop)
Q.startWorker(untilEmpty: false)
loop.advanceTime(by: .seconds(5))
await fulfillment(of: [exp], timeout: kMinTimeout)

Expand Down
2 changes: 1 addition & 1 deletion Tests/Scheduler/FrequencyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ final class FrequencyTests: XCTestCase {
return
}

XCTAssertGreaterThan(next, .hours(24 * 365 * 10))
XCTAssertGreaterThan(next, .seconds(60 * 60 * 24 * 365 * 10))
}

func testNoNext() {
Expand Down
45 changes: 9 additions & 36 deletions Tests/Scheduler/SchedulerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,37 @@ import AlchemyTest
import NIOEmbedded

final class SchedulerTests: TestCase<TestApp> {
private var scheduler = Scheduler()
private var loop = EmbeddedEventLoop()
private var queue = Queue.fake()

override func setUp() {
super.setUp()
self.scheduler = Scheduler()
self.loop = EmbeddedEventLoop()
self.queue = Queue.fake()
}

func testScheduleTask() {
makeSchedule().everyDay()
scheduler.start(on: loop)
loop.advanceTime(by: .hours(24))
waitForExpectations(timeout: 0.1)
makeSchedule().everySecond()
app.background("schedule")
waitForExpectations(timeout: 2)
}

func testScheduleJob() async throws {
scheduler.job(TestJob()).everyDay()
scheduler.start(on: loop)
loop.advanceTime(by: .hours(24))
try await Task.sleep(nanoseconds: 1 * 1_000_000)
Schedule.job(TestJob()).everySecond()
app.background("schedule")
try await Task.sleep(for: .seconds(1))
await queue.assertPushed(TestJob.self)
}

func testNoRunWithoutStart() {
makeSchedule(invertExpect: true).everyDay()
waitForExpectations(timeout: kMinTimeout)
}

func testStart() {
makeSchedule().everyDay()
scheduler.start(on: loop)
loop.advanceTime(by: .hours(24))
waitForExpectations(timeout: kMinTimeout)
}

func testStartTwiceRunsOnce() {
makeSchedule().everyDay()
scheduler.start(on: loop)
scheduler.start(on: loop)
loop.advanceTime(by: .hours(24))
waitForExpectations(timeout: kMinTimeout)
}

func testDoesntRunNoNext() {
makeSchedule(invertExpect: true).cron("0 0 0 11 9 * 1993")
scheduler.start(on: loop)
loop.advanceTime(by: .hours(24))
waitForExpectations(timeout: kMinTimeout)
app.background("schedule")
waitForExpectations(timeout: 2)
}

private func makeSchedule(invertExpect: Bool = false) -> Frequency {
let exp = expectation(description: "")
exp.isInverted = invertExpect
var didRun = false
return scheduler.task {
return Schedule.task {
// Don't let the schedule fullfill this expectation twice.
guard !didRun else { return }
didRun = true
Expand Down

0 comments on commit e9db94e

Please sign in to comment.