/** * Adds a job to the JobRunner instance. * * @param JobDefinition $definition Job definition (e.g. interval). * @throws InvalidArgumentException If the given class does not subclass Job. * @return void */ public function addJob(JobDefinition $definition) { $class = $definition->getClassName(); $reflection = new ReflectionClass($class); if (!$reflection->isSubclassOf(Job::class)) { $this->logger->error("{$reflection->getShortName()} does not subclass " . Job::class); throw new InvalidArgumentException("{$reflection->getShortName()} must subclass " . Job::class); } if (isset($this->jobs[$class])) { $this->logger->warning("{$reflection->getShortName()} is already registered, skipping"); return; } // If we have a run_time and interval set, we will ignore the interval when checking if job can run. if (!is_null($definition->getInterval()) && !is_null($definition->getRunTime())) { $definition->setInterval(null); $this->logger->warning("Both run_time and interval are set for {$reflection->getShortName()} — " . "prioritizing run_time"); } // Set internal definitions $definition->setLastRunTimeStart(null); $definition->setLastRunTimeFinish(null); $definition->setReflection($reflection); // Add to job list, using defaults where necessary $this->jobs[$class] = $definition; $this->createJobBuckets($class); $this->logger->info("Registered job {$reflection->getShortName()} -- " . ($definition->getEnabled() ? "enabled" : "disabled")); }
/** * Tests adding a job class. * @return void */ public function testAddJob() { $mock = m::mock('fork_daemon'); $jr = new JobRunner($mock); // Make sure buckets are created correctly for the job $mock->shouldReceive('add_bucket')->with(JobStub::class)->once(); $mock->shouldReceive('max_children_set')->with(1, JobStub::class)->once(); $mock->shouldReceive('register_child_run')->with([$jr, 'processWork'], JobStub::class)->once(); $mock->shouldReceive('register_parent_child_exit')->with([$jr, 'parentChildExit'], JobStub::class)->once(); $mock->shouldReceive('child_max_run_time_set')->with(172800, JobStub::class)->once(); // Check Job added correctly $jr->addJob(new JobDefinition(JobStub::class)); $jobs = $jr->getJobs(); $this->assertArrayHasKey(JobStub::class, $jobs); $this->assertCount(1, $jobs); // Check job default definitions $job = $jobs[JobStub::class]; $this->assertInstanceOf(JobDefinition::class, $job); // Check enabled by default, and ReflectionClass saved $this->assertTrue($job->getEnabled()); $this->assertInstanceOf(ReflectionClass::class, $job->getReflection()); // Adding it twice should have no effect $jr->addJob(new JobDefinition(JobStub::class)); $this->assertArrayHasKey(JobStub::class, $jobs); $this->assertCount(1, $jobs); // Try again, setting some definition values $jr = new JobRunner(); $jd = new JobDefinition(JobStub::class, false, null, 3600); // should not be retained $jd->setLastRunTimeStart(time()); $jd->setLastRunTimeFinish(time()); $jr->addJob($jd); $job = $jr->getJobs()[JobStub::class]; $this->assertInstanceOf(JobDefinition::class, $job); $this->assertFalse($job->getEnabled()); $this->assertEquals(3600, $job->getInterval()); // Should not retain given values $this->assertEmpty($job->getLastRunTimeStart()); $this->assertEmpty($job->getLastRunTimeFinish()); $this->assertInstanceOf(ReflectionClass::class, $job->getReflection()); // Add a job with a run_time and interval set to see that interval is ignored and set back to null $definition = new JobDefinition(JobStub::class, true, '12:00', 5); $jr = new JobRunner(); $jr->addJob($definition); $updated_jd = $jr->getJob($definition->getClassName()); $this->assertNull($updated_jd->getInterval()); // Test adding a class extending JobDefinition $jr = new JobRunner(); $jr->addJob(new ExtendingJobDefinition(JobStub::class)); $this->assertInstanceOf(JobDefinition::class, $jr->getJob(JobStub::class)); // Adding a non-Job class should throw an exception $this->setExpectedException(Exception::class); $jr = new JobRunner(); $jr->addJob(new JobDefinition(stdClass::class)); }