Fix bug in job eligibility sorting after a job deletion.

This commit is contained in:
Greyson Parrelli
2025-11-18 19:58:45 -05:00
parent 92389284a5
commit c46a005758
2 changed files with 39 additions and 1 deletions

View File

@@ -362,7 +362,6 @@ class FastJobStorage(private val jobDatabase: JobDatabase) : JobStorage {
compareByDescending<MinimalJobSpec> { it.globalPriority } compareByDescending<MinimalJobSpec> { it.globalPriority }
.thenByDescending { it.queuePriority } .thenByDescending { it.queuePriority }
.thenBy { it.createTime } .thenBy { it.createTime }
.thenBy { it.id }
) )
?.let { placeJobInEligibleList(it) } ?.let { placeJobInEligibleList(it) }
} }

View File

@@ -829,6 +829,45 @@ class FastJobStorageTest {
assertThat(subject.getNextEligibleJob(20, NO_PREDICATE)).isEqualTo(fullSpec1.jobSpec) assertThat(subject.getNextEligibleJob(20, NO_PREDICATE)).isEqualTo(fullSpec1.jobSpec)
} }
@Test
fun `getNextEligibleJob - job chain with same createTime processes in correct order`() {
// Simulates a real job chain where all jobs are created in the same millisecond
// Jobs should process in dependency order, not alphabetical ID order
val job1 = FullSpec(
jobSpec(id = "z-first", factoryKey = "f1", queueKey = "q1", createTime = 1000),
emptyList(),
emptyList()
)
val job2 = FullSpec(
jobSpec(id = "m-second", factoryKey = "f2", queueKey = "q1", createTime = 1000),
emptyList(),
listOf(DependencySpec(jobId = "m-second", dependsOnJobId = "z-first", isMemoryOnly = false))
)
val job3 = FullSpec(
jobSpec(id = "a-third", factoryKey = "f3", queueKey = "q1", createTime = 1000),
emptyList(),
listOf(DependencySpec(jobId = "a-third", dependsOnJobId = "m-second", isMemoryOnly = false))
)
val subject = FastJobStorage(mockDatabase(listOf(job1, job2, job3)))
subject.init()
// First eligible should be job1 (no dependencies)
val first = subject.getNextEligibleJob(2000, NO_PREDICATE)
assertThat(first).isNotNull().prop(JobSpec::id).isEqualTo("z-first")
subject.deleteJob("z-first")
// After deleting job1, job2 should be eligible (dependency resolved)
val second = subject.getNextEligibleJob(2000, NO_PREDICATE)
assertThat(second).isNotNull().prop(JobSpec::id).isEqualTo("m-second")
subject.deleteJob("m-second")
// After deleting job2, job3 should be eligible
val third = subject.getNextEligibleJob(2000, NO_PREDICATE)
assertThat(third).isNotNull().prop(JobSpec::id).isEqualTo("a-third")
}
@Test @Test
fun `getEligibleJobCount - general`() { fun `getEligibleJobCount - general`() {
val subject = FastJobStorage(mockDatabase(DataSet1.FULL_SPECS)) val subject = FastJobStorage(mockDatabase(DataSet1.FULL_SPECS))