Вход Регистрация
Файл: vendor/laravel/framework/src/Illuminate/Foundation/Cloud/Queue.php
Строк: 651
<?php

namespace IlluminateFoundationCloud;

use 
CarbonCarbonImmutable;
use 
IlluminateContractsQueueClearableQueue;
use 
IlluminateContractsQueueQueue as QueueContract;
use 
IlluminateFoundationApplication;
use 
IlluminateHttpClientConnectionException;
use 
IlluminateHttpClientRequestException;
use 
IlluminateSupportFacadesHttp;
use 
IlluminateSupportStringable;
use 
IlluminateSupportTraitsForwardsCalls;
use 
SymfonyComponentConsoleInputArgvInput;

class 
Queue implements QueueContractClearableQueue
{
    use 
ForwardsCalls;

    
/**
     * The currently processing job.
     *
     * @var IlluminateContractsQueueJob|null
     */
    
protected $processingJob null;

    
/**
     * The queue for the currently processing job.
     *
     * @var string|null
     */
    
protected $processingQueue null;

    
/**
     * The date the last job started processing.
     *
     * @var CarbonCarbonImmutable
     */
    
protected $processingJobStartedAt null;

    
/**
     * Create a new Queue instance.
     */
    
public function __construct(
        protected 
Application $app,
        protected 
QueueContract $queue,
        protected 
Events $events,
        protected array 
$config,
    ) {
        
//
    
}

    
/**
     * Get the size of the queue.
     *
     * @param  string|null  $queue
     * @return int
     */
    
public function size($queue null)
    {
        return 
$this->queue->size(...func_get_args());
    }

    
/**
     * Get the number of pending jobs.
     *
     * @param  string|null  $queue
     * @return int
     */
    
public function pendingSize($queue null)
    {
        return 
$this->queue->pendingSize(...func_get_args());
    }

    
/**
     * Get the number of delayed jobs.
     *
     * @param  string|null  $queue
     * @return int
     */
    
public function delayedSize($queue null)
    {
        return 
$this->queue->delayedSize(...func_get_args());
    }

    
/**
     * Get the number of reserved jobs.
     *
     * @param  string|null  $queue
     * @return int
     */
    
public function reservedSize($queue null)
    {
        return 
$this->queue->reservedSize(...func_get_args());
    }

    
/**
     * Get the creation timestamp of the oldest pending job, excluding delayed jobs.
     *
     * @param  string|null  $queue
     * @return int|null
     */
    
public function creationTimeOfOldestPendingJob($queue null)
    {
        return 
$this->queue->creationTimeOfOldestPendingJob(...func_get_args());
    }

    
/**
     * Push a new job onto the queue.
     *
     * @param  string|object  $job
     * @param  mixed  $data
     * @param  string|null  $queue
     * @return mixed
     */
    
public function push($job$data ''$queue null)
    {
        return 
$this->queue->push(...func_get_args());
    }

    
/**
     * Push a new job onto the queue.
     *
     * @param  string  $queue
     * @param  string|object  $job
     * @param  mixed  $data
     * @return mixed
     */
    
public function pushOn($queue$job$data '')
    {
        return 
$this->queue->pushOn(...func_get_args());
    }

    
/**
     * Push a raw payload onto the queue.
     *
     * @param  string  $payload
     * @param  string|null  $queue
     * @return mixed
     */
    
public function pushRaw($payload$queue null, array $options = [])
    {
        
$result $this->queue->pushRaw(...func_get_args());

        
$this->finishQueueingJob($queue);

        return 
$result;
    }

    
/**
     * Push a new job onto the queue after (n) seconds.
     *
     * @param  DateTimeInterface|DateInterval|int  $delay
     * @param  string|object  $job
     * @param  mixed  $data
     * @param  string|null  $queue
     * @return mixed
     */
    
public function later($delay$job$data ''$queue null)
    {
        return 
$this->queue->later(...func_get_args());
    }

    
/**
     * Push a new job onto a specific queue after (n) seconds.
     *
     * @param  string  $queue
     * @param  DateTimeInterface|DateInterval|int  $delay
     * @param  string|object  $job
     * @param  mixed  $data
     * @return mixed
     */
    
public function laterOn($queue$delay$job$data '')
    {
        return 
$this->queue->laterOn(...func_get_args());
    }

    
/**
     * Push an array of jobs onto the queue.
     *
     * @param  array  $jobs
     * @param  mixed  $data
     * @param  string|null  $queue
     * @return mixed
     */
    
public function bulk($jobs$data ''$queue null)
    {
        return 
$this->queue->bulk(...func_get_args());
    }

    
/**
     * Pop the next job off of the queue.
     *
     * Jobs come straight from SQS unless the cloud-agent is enabled.
     *
     * When cloud-agent is enabled, we long-poll the agent's runtime socket instead.
     *
     * @param  string|null  $queue
     * @return IlluminateContractsQueueJob|null
     */
    
public function pop($queue null)
    {
        
$this->finishProcessingJob();

        
$job $this->usesAgent($queue)
            ? 
$this->popFromAgent()
            : 
$this->queue->pop(...func_get_args());

        
$this->startProcessingJob($queue$job);

        return 
$job;
    }

    
/**
     * Long-poll the cloud-agent's runtime socket and wrap the next message in a CloudJob.
     *
     * @return IlluminateFoundationCloudCloudJob|null
     */
    
protected function popFromAgent()
    {
        
$data $this->requestNextJobFromAgent();

        if (! (
is_array($data) && is_string($messageId $data['messageId'] ?? null) && $messageId !== '')) {
            return 
null;
        }

        
// Coerce a non-string handle to null so a malformed response degrades gracefully...
        
$receiptHandle is_string($handle $data['receiptHandle'] ?? null) ? $handle null;

        return new 
CloudJob(
            
$this->queue->getContainer(),
            
$this->queue->getSqs(),
            [
                
'MessageId' => $messageId,
                
'ReceiptHandle' => $receiptHandle,
                
'Body' => is_string($body $data['body'] ?? null) ? $body '',
                
'Attributes' => $data['attributes'] ?? [],
            ],
            
$this->queue->getConnectionName(),
            
$data['queueUrl'] ?? null,
            
fn (string $status, ?int $delay) => $this->reportJobStatusToAgent(
                
$messageId$receiptHandle$status$delay
            
),
            
$this->config['connection']['overflow'] ?? [],
        );
    }

    
/**
     * Long-poll the agent's runtime socket (GET /next) for the next job.
     *
     * @throws IlluminateFoundationCloudAgentUnreachableException
     */
    
protected function requestNextJobFromAgent(): ?array
    {
        try {
            
$response $this->agentRequest()
                ->
timeout(65)
                ->
get('/next');
        } catch (
ConnectionException $e) {
            throw new 
AgentUnreachableException(
                
'The Laravel Cloud agent runtime socket is unreachable.'previous$e
            
);
        }

        if (
$response->status() === 204) {
            return 
null;
        }

        if (! 
$response->ok()) {
            throw new 
AgentUnreachableException(
                
"The Laravel Cloud agent returned HTTP {$response->status()} from GET /next."
            
);
        }

        if (! 
is_array($data $response->json())) {
            throw new 
AgentUnreachableException(
                
'The Laravel Cloud agent returned a non-array body from GET /next.'
            
);
        }

        return 
$data;
    }

    
/**
     * Report a job's terminal outcome back to the agent (POST /result).
     *
     * @throws IlluminateHttpClientRequestException
     * @throws IlluminateFoundationCloudAgentUnreachableException
     */
    
protected function reportJobStatusToAgent(string $messageId, ?string $receiptHandlestring $status, ?int $delay null): void
    
{
        try {
            
$this->agentRequest()
                ->
timeout(10)
                ->
throw()
                ->
retry(3100fn ($exception) => $exception instanceof ConnectionException)
                ->
post('/result'array_filter([
                    
'messageId' => $messageId,
                    
'receiptHandle' => $receiptHandle,
                    
'status' => $status,
                    
'delay' => $delay,
                ], 
fn ($value) => $value !== null));
        } catch (
ConnectionException $e) {
            throw new 
AgentUnreachableException(
                
'The Laravel Cloud agent runtime socket is unreachable.'previous$e
            
);
        } catch (
RequestException $e) {
            if (
$e->response->serverError()) {
                throw new 
AgentUnreachableException(
                    
"The Laravel Cloud agent returned HTTP {$e->response->status()} from POST /result."previous$e
                
);
            }

            throw 
$e;
        }
    }

    
/**
     * Get a pending HTTP request bound to the agent's Unix runtime socket.
     *
     * @return IlluminateHttpClientPendingRequest
     */
    
protected function agentRequest()
    {
        return 
Http::baseUrl('http://localhost')->withOptions([
            
'curl' => [
                
CURLOPT_UNIX_SOCKET_PATH => $this->config['agent']['socket'] ?? '/tmp/cloud-agent.sock',
            ],
        ]);
    }

    
/**
     * Delete all of the jobs from the queue.
     *
     * @param  string  $queue
     * @return int
     */
    
public function clear($queue)
    {
        return 
$this->queue->clear(...func_get_args());
    }

    
/**
     * Determine whether the next job should be received from the in-container cloud-agent.
     *
     * @param  string|null  $queue
     */
    
protected function usesAgent($queue null): bool
    
{
        return (
$this->config['agent']['enabled'] ?? false)
            && 
$this->app->runningConsoleCommand('queue:work')
            && 
$this->queue->getQueue($queue) === $this->queue->getQueue($this->workerQueue());
    }

    
/**
     * Get the queue the running queue:work worker is processing.
     *
     * @return string
     */
    
protected function workerQueue()
    {
        return (new 
ArgvInput)->getParameterOption('--queue')
            ?: (
$this->config['queue'] ?? 'default');
    }

    
/**
     * Get the connection name for the queue.
     *
     * @return string
     */
    
public function getConnectionName()
    {
        return 
$this->queue->getConnectionName();
    }

    
/**
     * Set the connection name for the queue.
     *
     * @param  string  $name
     * @return $this
     */
    
public function setConnectionName($name)
    {
        
$this->queue->setConnectionName(...func_get_args());

        return 
$this;
    }

    
/**
     * Set the queue configuration array.
     *
     * @param  array  $config
     * @return $this
     */
    
public function setConfig($config)
    {
        
$this->config $config;

        
$this->queue->setConfig($config['connection']);

        return 
$this;
    }

    
/**
     * Get the queueable options from the job.
     *
     * @param  mixed  $job
     * @param  string|null  $queue
     * @param  string  $payload
     * @param  DateTimeInterface|DateInterval|int|null  $delay
     * @return array{DelaySeconds?: int, MessageGroupId?: string, MessageDeduplicationId?: string}
     */
    
public function getQueueableOptions($job$queue$payload$delay null): array
    {
        if (! 
method_exists($this->queue'getQueueableOptions')) {
            return [];
        }

        return 
$this->queue->getQueueableOptions(...func_get_args());
    }

    
/**
     * Finish processing the current job and emit a queue event.
     *
     * @param  string  $default
     * @param  CarbonCarbonImmutable|null  $timestamp
     * @return void
     */
    
public function finishProcessingJob($default 'processed'$timestamp null)
    {
        if (! 
$this->processingJob) {
            return;
        }

        
$timestamp ??= CarbonImmutable::now('UTC');

        
$this->events->emit([
            
'_cloud_event' => 'queue',
            
'timestamp' => $timestamp->toDateTimeString('microsecond'),
            
'type' => match (true) {
                
$this->processingJob->hasFailed() => 'failed',
                
$this->processingJob->isReleased() => 'released',
                default => 
$default,
            },
            
'queue' => $this->processingQueue,
            
'duration_ms' => (int) $this->processingJobStartedAt->diffInMilliseconds($timestamp),
        ]);

        
$this->processingQueue
            
$this->processingJob
            
$this->processingJobStartedAt
            
null;
    }

    
/**
     * Last job details resolver.
     *
     * @return array{queue: string, attempts: int, started_at: CarbonImmutable}
     */
    
public function processingJobDetails()
    {
        return [
            
'queue' => $this->processingQueue,
            
'attempts' => $this->processingJob->attempts(),
            
'started_at' => $this->processingJobStartedAt,
        ];
    }

    
/**
     * Handle jobs finishing being queued.
     *
     * @param  string  $queue
     */
    
public function finishQueueingJob($queue)
    {
        
$this->events->emit([
            
'_cloud_event' => 'queue',
            
'timestamp' => CarbonImmutable::now('UTC')->toDateTimeString('microsecond'),
            
'type' => 'queued',
            
'queue' => $this->normalizeQueue($queue),
        ]);
    }

    
/**
     * Handle a job being popped.
     *
     * @param  string|null  $queue
     * @param  IlluminateContractsQueueJob|null  $job
     * @return void
     */
    
protected function startProcessingJob($queue$job)
    {
        if (! 
$job) {
            return;
        }

        
$this->processingJob $job;
        
$this->processingQueue $this->normalizeQueue($queue);
        
$this->processingJobStartedAt CarbonImmutable::now('UTC');

        
$this->events->emit([
            
'_cloud_event' => 'queue',
            
'timestamp' => $this->processingJobStartedAt->toDateTimeString('microsecond'),
            
'type' => 'started',
            
'queue' => $this->processingQueue,
        ]);
    }

    
/**
     * Normalize the queue name.
     *
     * @param  string|null  $queue
     * @return string
     */
    
public function normalizeQueue($queue)
    {
        
$prefix $this->config['connection']['prefix'] ?? null;
        
$suffix $this->config['connection']['suffix'] ?? null;

        return (new 
Stringable($this->queue->getQueue($queue)))
            ->
when($prefixfn ($str) => $str->chopStart($prefix.'/'))
            ->
when($suffixfn ($str) => $str->endsWith('.fifo')
                ? 
$str->chopEnd('.fifo')->chopEnd($suffix)->append('.fifo')
                : 
$str->chopEnd($suffix))
            ->
toString();
    }

    
/**
     * Dynamically pass method calls to the underlying queue.
     *
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    
public function __call($method$parameters)
    {
        return 
$this->forwardDecoratedCallTo($this->queue$method$parameters);
    }
}
Онлайн: 2
Реклама