Skip to content
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

Update from Hummingbird Project Template #41

Merged
merged 3 commits into from
Nov 28, 2024
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
6 changes: 1 addition & 5 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ concurrency:

jobs:
validate:
runs-on: macOS-latest
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Install Dependencies
run: |
brew install mint
mint install NickLockwood/[email protected] --no-link
- name: run script
run: ./scripts/validate.sh
63 changes: 63 additions & 0 deletions .swift-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"version" : 1,
"indentation" : {
"spaces" : 4
},
"tabWidth" : 4,
"fileScopedDeclarationPrivacy" : {
"accessLevel" : "private"
},
"spacesAroundRangeFormationOperators" : false,
"indentConditionalCompilationBlocks" : false,
"indentSwitchCaseLabels" : false,
"lineBreakAroundMultilineExpressionChainComponents" : false,
"lineBreakBeforeControlFlowKeywords" : false,
"lineBreakBeforeEachArgument" : true,
"lineBreakBeforeEachGenericRequirement" : true,
"lineLength" : 150,
"maximumBlankLines" : 1,
"respectsExistingLineBreaks" : true,
"prioritizeKeepingFunctionOutputTogether" : true,
"multiElementCollectionTrailingCommas" : true,
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AlwaysUseLiteralForEmptyCollectionInit" : false,
"AlwaysUseLowerCamelCase" : false,
"AmbiguousTrailingClosureOverload" : true,
"BeginDocumentationCommentWithOneLineSummary" : false,
"DoNotUseSemicolons" : true,
"DontRepeatTypeInStaticProperties" : true,
"FileScopedDeclarationPrivacy" : true,
"FullyIndirectEnum" : true,
"GroupNumericLiterals" : true,
"IdentifiersMustBeASCII" : true,
"NeverForceUnwrap" : false,
"NeverUseForceTry" : false,
"NeverUseImplicitlyUnwrappedOptionals" : false,
"NoAccessLevelOnExtensionDeclaration" : true,
"NoAssignmentInExpressions" : true,
"NoBlockComments" : true,
"NoCasesWithOnlyFallthrough" : true,
"NoEmptyTrailingClosureParentheses" : true,
"NoLabelsInCasePatterns" : true,
"NoLeadingUnderscores" : false,
"NoParensAroundConditions" : true,
"NoVoidReturnOnFunctionSignature" : true,
"OmitExplicitReturns" : true,
"OneCasePerLine" : true,
"OneVariableDeclarationPerLine" : true,
"OnlyOneTrailingClosureArgument" : true,
"OrderedImports" : true,
"ReplaceForEachWithForLoop" : true,
"ReturnVoidInsteadOfEmptyTuple" : true,
"UseEarlyExits" : false,
"UseExplicitNilCheckInConditions" : false,
"UseLetInEveryBoundCaseVariable" : false,
"UseShorthandTypeNames" : true,
"UseSingleLinePropertyGetter" : false,
"UseSynthesizedInitializer" : false,
"UseTripleSlashForDocumentationComments" : true,
"UseWhereClausesInForLoops" : false,
"ValidateDocumentationComments" : false
}
}
26 changes: 0 additions & 26 deletions .swiftformat

This file was deleted.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ The main development branch of the repository is `main`.

### Formatting

We use Nick Lockwood's SwiftFormat for formatting code. PRs will not be accepted if they haven't be formatted. The current version of SwiftFormat we are using is v0.53.10.
We use Apple's swift-format for formatting code. PRs will not be accepted if they haven't be formatted.
13 changes: 8 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ let package = Package(
name: "swift-jobs",
platforms: [.macOS(.v14), .iOS(.v17), .tvOS(.v17)],
products: [
.library(name: "Jobs", targets: ["Jobs"]),
.library(name: "Jobs", targets: ["Jobs"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.0.0"),
Expand All @@ -34,9 +34,12 @@ let package = Package(
swiftSettings: swiftSettings
),
// test targets
.testTarget(name: "JobsTests", dependencies: [
.byName(name: "Jobs"),
.product(name: "Atomics", package: "swift-atomics"),
]),
.testTarget(
name: "JobsTests",
dependencies: [
.byName(name: "Jobs"),
.product(name: "Atomics", package: "swift-atomics"),
]
),
]
)
26 changes: 15 additions & 11 deletions Sources/Jobs/JobMetricsHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ internal enum JobMetricsHelper {
// with something like count(swif_jobs_meter{status="processing"}
// unless on(jobID) (swif_jobs_meter{status="queued"})
// or (swif_jobs_meter{status="completed")) or vector(0)
Meter(label: JobMetricsHelper.meterLabel, dimensions: [
("status", JobMetricsHelper.JobStatus.completed.rawValue),
("jobID", jobID),
]).increment()
Meter(
label: JobMetricsHelper.meterLabel,
dimensions: [
("status", JobMetricsHelper.JobStatus.completed.rawValue),
("jobID", jobID),
]
).increment()

if retrying {
Counter(
Expand All @@ -66,15 +69,16 @@ internal enum JobMetricsHelper {
return
}

let jobStatus: JobStatus = if let error {
if error is CancellationError {
.cancelled
let jobStatus: JobStatus =
if let error {
if error is CancellationError {
.cancelled
} else {
.failed
}
} else {
.failed
.succeeded
}
} else {
.succeeded
}

let dimensions: [(String, String)] = [
("name", name),
Expand Down
14 changes: 10 additions & 4 deletions Sources/Jobs/JobParameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ extension JobParameters {
}

/// Added so it is possible to push JobParameters referenced as Existentials to a Job queue
@discardableResult public func push<Queue: JobQueueDriver>(to jobQueue: JobQueue<Queue>, options: JobOptions = .init()) async throws -> Queue.JobID {
return try await jobQueue.push(self, options: options)
@discardableResult public func push<Queue: JobQueueDriver>(
to jobQueue: JobQueue<Queue>,
options: JobOptions = .init()
) async throws -> Queue.JobID {
try await jobQueue.push(self, options: options)
}
}

Expand All @@ -36,8 +39,11 @@ extension JobQueue {
/// - parameters: parameters for the job
/// - options: JobOptions
/// - Returns: Identifier of queued job
@discardableResult public func push<Parameters: JobParameters>(_ parameters: Parameters, options: JobOptions = .init()) async throws -> Queue.JobID {
return try await self.push(id: Parameters.jobID, parameters: parameters, options: options)
@discardableResult public func push<Parameters: JobParameters>(
_ parameters: Parameters,
options: JobOptions = .init()
) async throws -> Queue.JobID {
try await self.push(id: Parameters.jobID, parameters: parameters, options: options)
}

/// Register job type
Expand Down
11 changes: 7 additions & 4 deletions Sources/Jobs/JobQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@ public struct JobQueue<Queue: JobQueueDriver>: Service {
let buffer = try self.queue.encode(id: id, parameters: parameters)
let jobName = id.name
let id = try await self.queue.push(buffer, options: options)
Meter(label: JobMetricsHelper.meterLabel, dimensions: [
("status", JobMetricsHelper.JobStatus.queued.rawValue),
("jobID", id.description),
]).increment()
Meter(
label: JobMetricsHelper.meterLabel,
dimensions: [
("status", JobMetricsHelper.JobStatus.queued.rawValue),
("jobID", id.description),
]
).increment()
self.logger.debug(
"Pushed Job",
metadata: ["JobID": .stringConvertible(id), "JobName": .string(jobName)]
Expand Down
77 changes: 49 additions & 28 deletions Sources/Jobs/JobQueueHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,30 @@ final class JobQueueHandler<Queue: JobQueueDriver>: Sendable {
let startTime = DispatchTime.now().uptimeNanoseconds
logger[metadataKey: "JobID"] = .stringConvertible(queuedJob.id)
// Decrement the current queue by 1
Meter(label: JobMetricsHelper.meterLabel, dimensions: [
("status", JobMetricsHelper.JobStatus.queued.rawValue),
("jobID", queuedJob.id.description),
]).decrement()

Meter(label: JobMetricsHelper.meterLabel, dimensions: [
("status", JobMetricsHelper.JobStatus.processing.rawValue),
("jobID", queuedJob.id.description),
]).increment()
Meter(
label: JobMetricsHelper.meterLabel,
dimensions: [
("status", JobMetricsHelper.JobStatus.queued.rawValue),
("jobID", queuedJob.id.description),
]
).decrement()

defer {
Meter(label: JobMetricsHelper.meterLabel, dimensions: [
Meter(
label: JobMetricsHelper.meterLabel,
dimensions: [
("status", JobMetricsHelper.JobStatus.processing.rawValue),
("jobID", queuedJob.id.description),
]).decrement()
]
).increment()

defer {
Meter(
label: JobMetricsHelper.meterLabel,
dimensions: [
("status", JobMetricsHelper.JobStatus.processing.rawValue),
("jobID", queuedJob.id.description),
]
).decrement()
}

let job: any JobInstanceProtocol
Expand All @@ -92,18 +101,24 @@ final class JobQueueHandler<Queue: JobQueueDriver>: Sendable {
} catch let error as JobQueueError where error == .unrecognisedJobId {
logger.debug("Failed to find Job with ID while decoding")
try await self.queue.failed(jobId: queuedJob.id, error: error)
Meter(label: JobMetricsHelper.discardedMeter, dimensions: [
("reason", "INVALID_JOB_ID"),
("jobID", queuedJob.id.description),
]).increment()
Meter(
label: JobMetricsHelper.discardedMeter,
dimensions: [
("reason", "INVALID_JOB_ID"),
("jobID", queuedJob.id.description),
]
).increment()
return
} catch {
logger.debug("Job failed to decode")
try await self.queue.failed(jobId: queuedJob.id, error: JobQueueError.decodeJobFailed)
Meter(label: JobMetricsHelper.discardedMeter, dimensions: [
("reason", "DECODE_FAILED"),
("jobID", queuedJob.id.description),
]).increment()
Meter(
label: JobMetricsHelper.discardedMeter,
dimensions: [
("reason", "DECODE_FAILED"),
("jobID", queuedJob.id.description),
]
).increment()
return
}
logger[metadataKey: "JobName"] = .string(job.name)
Expand Down Expand Up @@ -163,21 +178,27 @@ final class JobQueueHandler<Queue: JobQueueDriver>: Sendable {

// Guard against negative queue values, this is needed because we call
// the job queue directly in the retrying step
Meter(label: JobMetricsHelper.meterLabel, dimensions: [
("status", JobMetricsHelper.JobStatus.queued.rawValue),
("jobID", newJobId.description),
]).increment()
Meter(
label: JobMetricsHelper.meterLabel,
dimensions: [
("status", JobMetricsHelper.JobStatus.queued.rawValue),
("jobID", newJobId.description),
]
).increment()

JobMetricsHelper.updateMetrics(
for: job.name,
jobID: queuedJob.id.description,
startTime: startTime,
retrying: true
)
logger.debug("Retrying Job", metadata: [
"attempts": .stringConvertible(attempts),
"delayedUntil": .stringConvertible(delay),
])
logger.debug(
"Retrying Job",
metadata: [
"attempts": .stringConvertible(attempts),
"delayedUntil": .stringConvertible(delay),
]
)
return
}
logger.debug("Finished Job")
Expand Down
4 changes: 2 additions & 2 deletions Sources/Jobs/JobRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct JobRegistry: Sendable {
}

func decode(_ buffer: ByteBuffer) throws -> any JobInstanceProtocol {
return try JSONDecoder().decode(AnyDecodableJob.self, from: buffer, userInfoConfiguration: self).job
try JSONDecoder().decode(AnyDecodableJob.self, from: buffer, userInfoConfiguration: self).job
}

func decode(jobName: String, from decoder: Decoder) throws -> any JobInstanceProtocol {
Expand All @@ -48,5 +48,5 @@ struct JobRegistry: Sendable {
return try jobDefinitionBuilder(decoder)
}

let builderTypeMap: NIOLockedValueBox < [String: @Sendable (Decoder) throws -> any JobInstanceProtocol]> = .init([:])
let builderTypeMap: NIOLockedValueBox<[String: @Sendable (Decoder) throws -> any JobInstanceProtocol]> = .init([:])
}
2 changes: 1 addition & 1 deletion Sources/Jobs/MemoryJobQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public final class MemoryQueue: JobQueueDriver {
/// - options: Job options
/// - Returns: Job ID
@discardableResult public func push(_ buffer: ByteBuffer, options: JobOptions) async throws -> JobID {
return try await self.queue.push(buffer, options: options)
try await self.queue.push(buffer, options: options)
}

public func finished(jobId: JobID) async throws {
Expand Down
15 changes: 8 additions & 7 deletions Sources/Jobs/Scheduler/JobSchedule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,16 @@ public struct JobSchedule: MutableCollection, Sendable {
}

func nextJob() -> (offset: Int, element: Element)? {
return self.lazy.enumerated().min(by: { $0.element.nextScheduledDate < $1.element.nextScheduledDate })
self.lazy.enumerated().min(by: { $0.element.nextScheduledDate < $1.element.nextScheduledDate })
}

mutating func updateNextScheduledDate(jobIndex: Int) {
let dateFrom: Date = switch self.self[jobIndex].accuracy {
case .latest: .now
case .all: self[jobIndex].nextScheduledDate
default: .now
}
let dateFrom: Date =
switch self.self[jobIndex].accuracy {
case .latest: .now
case .all: self[jobIndex].nextScheduledDate
default: .now
}
if let nextScheduledDate = self[jobIndex].schedule.nextDate(after: dateFrom) {
self[jobIndex].nextScheduledDate = nextScheduledDate
} else {
Expand Down Expand Up @@ -213,7 +214,7 @@ extension JobSchedule {
public var endIndex: Index { self.elements.endIndex }
/// Access element at specific position
public subscript(_ index: Index) -> Element {
get { return self.elements[index] }
get { self.elements[index] }
set { self.elements[index] = newValue }
}

Expand Down
Loading