/** @var StatsdDataFactoryInterface */
protected $stats;
- /** @var BagOStuff */
- protected $dupCache;
+ /** @var WANObjectCache */
+ protected $wanCache;
const QOS_ATOMIC = 1; // integer; "all-or-nothing" job insertions
/**
* @param array $params
+ * - type : A job type
+ * - domain : A DB domain ID
+ * - wanCache : An instance of WANObjectCache to use for caching [default: none]
+ * - stats : An instance of StatsdDataFactoryInterface [default: none]
+ * - claimTTL : Seconds a job can be claimed for exclusive execution [default: forever]
+ * - maxTries : Total times a job can be tried, assuming claims expire [default: 3]
+ * - order : Queue order, one of ("fifo", "timestamp", "random") [default: variable]
+ * - readOnlyReason : Mark the queue as read-only with this reason [default: false]
* @throws JobQueueError
*/
protected function __construct( array $params ) {
}
$this->readOnlyReason = $params['readOnlyReason'] ?? false;
$this->stats = $params['stats'] ?? new NullStatsdDataFactory();
- $this->dupCache = $params['stash'] ?? new EmptyBagOStuff();
+ $this->wanCache = $params['wanCache'] ?? WANObjectCache::newEmpty();
}
/**
* Outside callers should use JobQueueGroup::pop() instead of this function.
*
* @throws JobQueueError
- * @return Job|bool Returns false if there are no jobs
+ * @return RunnableJob|bool Returns false if there are no jobs
*/
final public function pop() {
$this->assertNotReadOnly();
/**
* @see JobQueue::pop()
- * @return Job|bool
+ * @return RunnableJob|bool
*/
abstract protected function doPop();
* This does nothing for certain queue classes or if "claimTTL" is not set.
* Outside callers should use JobQueueGroup::ack() instead of this function.
*
- * @param Job $job
+ * @param RunnableJob $job
* @return void
* @throws JobQueueError
*/
- final public function ack( Job $job ) {
+ final public function ack( RunnableJob $job ) {
$this->assertNotReadOnly();
if ( $job->getType() !== $this->type ) {
throw new JobQueueError( "Got '{$job->getType()}' job; expected '{$this->type}'." );
/**
* @see JobQueue::ack()
- * @param Job $job
+ * @param RunnableJob $job
*/
- abstract protected function doAck( Job $job );
+ abstract protected function doAck( RunnableJob $job );
/**
* Register the "root job" of a given job into the queue for de-duplication.
* @return bool
*/
protected function doDeduplicateRootJob( IJobSpecification $job ) {
- if ( !$job->hasRootJobParams() ) {
+ $params = $job->hasRootJobParams() ? $job->getRootJobParams() : null;
+ if ( !$params ) {
throw new JobQueueError( "Cannot register root job; missing parameters." );
}
- $params = $job->getRootJobParams();
$key = $this->getRootJobCacheKey( $params['rootJobSignature'] );
- // Callers should call JobQueueGroup::push() before this method so that if the insert
- // fails, the de-duplication registration will be aborted. Since the insert is
- // deferred till "transaction idle", do the same here, so that the ordering is
- // maintained. Having only the de-duplication registration succeed would cause
- // jobs to become no-ops without any actual jobs that made them redundant.
- $timestamp = $this->dupCache->get( $key ); // current last timestamp of this job
- if ( $timestamp && $timestamp >= $params['rootJobTimestamp'] ) {
+ // Callers should call JobQueueGroup::push() before this method so that if the
+ // insert fails, the de-duplication registration will be aborted. Having only the
+ // de-duplication registration succeed would cause jobs to become no-ops without
+ // any actual jobs that made them redundant.
+ $timestamp = $this->wanCache->get( $key ); // last known timestamp of such a root job
+ if ( $timestamp !== false && $timestamp >= $params['rootJobTimestamp'] ) {
return true; // a newer version of this root job was enqueued
}
// Update the timestamp of the last root job started at the location...
- return $this->dupCache->set( $key, $params['rootJobTimestamp'], self::ROOTJOB_TTL );
+ return $this->wanCache->set( $key, $params['rootJobTimestamp'], self::ROOTJOB_TTL );
}
/**
* Check if the "root" job of a given job has been superseded by a newer one
*
- * @param Job $job
+ * @param IJobSpecification $job
* @throws JobQueueError
* @return bool
*/
- final protected function isRootJobOldDuplicate( Job $job ) {
+ final protected function isRootJobOldDuplicate( IJobSpecification $job ) {
if ( $job->getType() !== $this->type ) {
throw new JobQueueError( "Got '{$job->getType()}' job; expected '{$this->type}'." );
}
- $isDuplicate = $this->doIsRootJobOldDuplicate( $job );
- return $isDuplicate;
+ return $this->doIsRootJobOldDuplicate( $job );
}
/**
* @see JobQueue::isRootJobOldDuplicate()
- * @param Job $job
+ * @param IJobSpecification $job
* @return bool
*/
- protected function doIsRootJobOldDuplicate( Job $job ) {
- if ( !$job->hasRootJobParams() ) {
+ protected function doIsRootJobOldDuplicate( IJobSpecification $job ) {
+ $params = $job->hasRootJobParams() ? $job->getRootJobParams() : null;
+ if ( !$params ) {
return false; // job has no de-deplication info
}
- $params = $job->getRootJobParams();
$key = $this->getRootJobCacheKey( $params['rootJobSignature'] );
// Get the last time this root job was enqueued
- $timestamp = $this->dupCache->get( $key );
+ $timestamp = $this->wanCache->get( $key );
+ if ( $timestamp === false || $params['rootJobTimestamp'] > $timestamp ) {
+ // Update the timestamp of the last known root job started at the location...
+ $this->wanCache->set( $key, $params['rootJobTimestamp'], self::ROOTJOB_TTL );
+ }
// Check if a new root job was started at the location after this one's...
return ( $timestamp && $timestamp > $params['rootJobTimestamp'] );
* @return string
*/
protected function getRootJobCacheKey( $signature ) {
- return $this->dupCache->makeGlobalKey(
+ return $this->wanCache->makeGlobalKey(
'jobqueue',
$this->domain,
$this->type,
return null; // not supported
}
+ /**
+ * @param string $command
+ * @param array $params
+ * @return Job
+ */
+ protected function factoryJob( $command, $params ) {
+ // @TODO: dependency inject this as a callback
+ return Job::factory( $command, $params );
+ }
+
/**
* @throws JobQueueReadOnlyError
*/