@@ -131,6 +131,10 @@ public final class JobRunner {
131131 SNLog ( " [JobRunner] Unable to add \( job. map { " \( $0. variant) " } ?? " unknown " ) job " )
132132 return
133133 }
134+ guard !canStartJob || updatedJob. id != nil else {
135+ SNLog ( " [JobRunner] Not starting \( job. map { " \( $0. variant) " } ?? " unknown " ) job due to missing id " )
136+ return
137+ }
134138
135139 queues. mutate { $0 [ updatedJob. variant] ? . add ( updatedJob, canStartJob: canStartJob) }
136140
@@ -150,6 +154,10 @@ public final class JobRunner {
150154 /// is in the future then the job won't be started
151155 public static func upsert( _ db: Database , job: Job ? , canStartJob: Bool = true ) {
152156 guard let job: Job = job else { return } // Ignore null jobs
157+ guard job. id != nil else {
158+ add ( db, job: job, canStartJob: canStartJob)
159+ return
160+ }
153161
154162 queues. wrappedValue [ job. variant] ? . upsert ( job, canStartJob: canStartJob)
155163
@@ -159,7 +167,7 @@ public final class JobRunner {
159167 }
160168 }
161169
162- @discardableResult public static func insert( _ db: Database , job: Job ? , before otherJob: Job ) -> Job ? {
170+ @discardableResult public static func insert( _ db: Database , job: Job ? , before otherJob: Job ) -> ( Int64 , Job ) ? {
163171 switch job? . behaviour {
164172 case . recurringOnActive, . recurringOnLaunch, . runOnceNextLaunch:
165173 SNLog ( " [JobRunner] Attempted to insert \( job. map { " \( $0. variant) " } ?? " unknown " ) job before the current one even though it's behaviour is \( job. map { " \( $0. behaviour) " } ?? " unknown " ) " )
@@ -173,6 +181,10 @@ public final class JobRunner {
173181 SNLog ( " [JobRunner] Unable to add \( job. map { " \( $0. variant) " } ?? " unknown " ) job " )
174182 return nil
175183 }
184+ guard let jobId: Int64 = updatedJob. id else {
185+ SNLog ( " [JobRunner] Unable to add \( job. map { " \( $0. variant) " } ?? " unknown " ) job due to missing id " )
186+ return nil
187+ }
176188
177189 queues. wrappedValue [ updatedJob. variant] ? . insert ( updatedJob, before: otherJob)
178190
@@ -181,7 +193,7 @@ public final class JobRunner {
181193 queues. wrappedValue [ updatedJob. variant] ? . start ( )
182194 }
183195
184- return updatedJob
196+ return ( jobId , updatedJob)
185197 }
186198
187199 public static func appDidFinishLaunching( ) {
@@ -499,6 +511,10 @@ private final class JobQueue {
499511 job. behaviour != . runOnceNextLaunch,
500512 job. nextRunTimestamp <= Date ( ) . timeIntervalSince1970
501513 else { return }
514+ guard job. id != nil else {
515+ SNLog ( " [JobRunner] Prevented attempt to add \( job. variant) job without id to queue " )
516+ return
517+ }
502518
503519 queue. mutate { $0. append ( job) }
504520 }
@@ -510,7 +526,7 @@ private final class JobQueue {
510526 /// is in the future then the job won't be started
511527 fileprivate func upsert( _ job: Job , canStartJob: Bool = true ) {
512528 guard let jobId: Int64 = job. id else {
513- add ( job, canStartJob : canStartJob )
529+ SNLog ( " [JobRunner] Prevented attempt to upsert \( job. variant ) job without id to queue " )
514530 return
515531 }
516532
@@ -535,6 +551,11 @@ private final class JobQueue {
535551 }
536552
537553 fileprivate func insert( _ job: Job , before otherJob: Job ) {
554+ guard job. id != nil else {
555+ SNLog ( " [JobRunner] Prevented attempt to insert \( job. variant) job without id to queue " )
556+ return
557+ }
558+
538559 // Insert the job before the current job (re-adding the current job to
539560 // the start of the queue if it's not in there) - this will mean the new
540561 // job will run and then the otherJob will run (or run again) once it's
@@ -634,7 +655,12 @@ private final class JobQueue {
634655 let jobIdsAlreadyRunning : Set < Int64 > = jobsCurrentlyRunning. wrappedValue
635656 let jobsAlreadyInQueue : Set < Int64 > = queue. wrappedValue. compactMap { $0. id } . asSet ( )
636657 let jobsToRun : [ Job ] = Storage . shared. read { db in
637- try Job . filterPendingJobs ( variants: jobVariants)
658+ try Job
659+ . filterPendingJobs (
660+ variants: jobVariants,
661+ excludeFutureJobs: true ,
662+ includeJobsWithDependencies: false
663+ )
638664 . filter ( !jobIdsAlreadyRunning. contains ( Job . Columns. id) ) // Exclude jobs already running
639665 . filter ( !jobsAlreadyInQueue. contains ( Job . Columns. id) ) // Exclude jobs already in the queue
640666 . fetchAll ( db)
@@ -709,6 +735,11 @@ private final class JobQueue {
709735 handleJobFailed ( nextJob, error: JobRunnerError . requiredInteractionIdMissing, permanentFailure: true )
710736 return
711737 }
738+ guard nextJob. id != nil else {
739+ SNLog ( " [JobRunner] \( queueContext) Unable to run \( nextJob. variant) job due to missing id " )
740+ handleJobFailed ( nextJob, error: JobRunnerError . jobIdMissing, permanentFailure: false )
741+ return
742+ }
712743
713744 // If the 'nextRunTimestamp' for the job is in the future then don't run it yet
714745 guard nextJob. nextRunTimestamp <= Date ( ) . timeIntervalSince1970 else {
@@ -787,7 +818,7 @@ private final class JobQueue {
787818 numJobsRunning = jobsCurrentlyRunning. count
788819 }
789820 detailsForCurrentlyRunningJobs. mutate { $0 = $0. setting ( nextJob. id, nextJob. details) }
790- SNLog ( " [JobRunner] \( queueContext) started job ( \( executionType == . concurrent ? " \( numJobsRunning) currently running, " : " " ) \( numJobsRemaining) remaining) " )
821+ SNLog ( " [JobRunner] \( queueContext) started \( nextJob . variant ) job (\( executionType == . concurrent ? " \( numJobsRunning) currently running, " : " " ) \( numJobsRemaining) remaining) " )
791822
792823 jobExecutor. run (
793824 nextJob,
@@ -809,7 +840,12 @@ private final class JobQueue {
809840 private func scheduleNextSoonestJob( ) {
810841 let jobIdsAlreadyRunning : Set < Int64 > = jobsCurrentlyRunning. wrappedValue
811842 let nextJobTimestamp : TimeInterval ? = Storage . shared. read { db in
812- try Job . filterPendingJobs ( variants: jobVariants, excludeFutureJobs: false )
843+ try Job
844+ . filterPendingJobs (
845+ variants: jobVariants,
846+ excludeFutureJobs: false ,
847+ includeJobsWithDependencies: false
848+ )
813849 . select ( . nextRunTimestamp)
814850 . filter ( !jobIdsAlreadyRunning. contains ( Job . Columns. id) ) // Exclude jobs already running
815851 . asRequest ( of: TimeInterval . self)
0 commit comments