DominionEnterprises\Mongo\Queue::get PHP Method

get() public method

Get a non running message from the queue.
public get ( array $query, integer $runningResetDuration, integer $waitDurationInMillis = 3000, integer $pollDurationInMillis = 200 ) : array | null
$query array in same format as \MongoDB\Collection::find() where top level fields do not contain operators. Lower level fields can however. eg: valid {a: {$gt: 1}, "b.c": 3}, invalid {$and: [{...}, {...}]}
$runningResetDuration integer second duration the message can stay unacked before it resets and can be retreived again.
$waitDurationInMillis integer millisecond duration to wait for a message.
$pollDurationInMillis integer millisecond duration to wait between polls.
return array | null the message or null if one is not found
    public function get(array $query, $runningResetDuration, $waitDurationInMillis = 3000, $pollDurationInMillis = 200)
    {
        if (!is_int($runningResetDuration)) {
            throw new \InvalidArgumentException('$runningResetDuration was not an int');
        }
        if (!is_int($waitDurationInMillis)) {
            throw new \InvalidArgumentException('$waitDurationInMillis was not an int');
        }
        if (!is_int($pollDurationInMillis)) {
            throw new \InvalidArgumentException('$pollDurationInMillis was not an int');
        }
        if ($pollDurationInMillis < 0) {
            $pollDurationInMillis = 0;
        }
        //reset stuck messages
        $this->collection->updateMany(['running' => true, 'resetTimestamp' => ['$lte' => new \MongoDB\BSON\UTCDateTime((int) (microtime(true) * 1000))]], ['$set' => ['running' => false]]);
        $completeQuery = ['running' => false];
        foreach ($query as $key => $value) {
            if (!is_string($key)) {
                throw new \InvalidArgumentException('key in $query was not a string');
            }
            $completeQuery["payload.{$key}"] = $value;
        }
        $completeQuery['earliestGet'] = ['$lte' => new \MongoDB\BSON\UTCDateTime((int) (microtime(true) * 1000))];
        $resetTimestamp = time() + $runningResetDuration;
        //ints overflow to floats
        if (!is_int($resetTimestamp)) {
            $resetTimestamp = $runningResetDuration > 0 ? self::MONGO_INT32_MAX : 0;
        }
        $resetTimestamp = min(max(0, $resetTimestamp * 1000), self::MONGO_INT32_MAX);
        $update = ['$set' => ['resetTimestamp' => new \MongoDB\BSON\UTCDateTime($resetTimestamp), 'running' => true]];
        $options = ['sort' => ['priority' => 1, 'created' => 1]];
        //ints overflow to floats, should be fine
        $end = microtime(true) + $waitDurationInMillis / 1000.0;
        $sleepTime = $pollDurationInMillis * 1000;
        //ints overflow to floats and already checked $pollDurationInMillis was positive
        if (!is_int($sleepTime)) {
            //ignore since testing a giant sleep takes too long
            //@codeCoverageIgnoreStart
            $sleepTime = PHP_INT_MAX;
        }
        //@codeCoverageIgnoreEnd
        while (true) {
            $message = $this->collection->findOneAndUpdate($completeQuery, $update, $options);
            //checking if _id exist because findAndModify doesnt seem to return null when it can't match the query on
            //older mongo extension
            if ($message !== null && array_key_exists('_id', $message)) {
                // findOneAndUpdate does not correctly return result according to typeMap options so just refetch.
                $message = $this->collection->findOne(['_id' => $message->_id]);
                //id on left of union operator so a possible id in payload doesnt wipe it out the generated one
                return ['id' => $message['_id']] + (array) $message['payload'];
            }
            if (microtime(true) >= $end) {
                return null;
            }
            usleep($sleepTime);
        }
        //ignore since always return from the function from the while loop
        //@codeCoverageIgnoreStart
    }