File: /home/xedaptot/ai.naniguide.com/app/Jobs/SendSingleMessage.php
<?php
namespace App\Jobs;
use App\Jobs\Concerns\JobControlAdapter;
use App\Jobs\Concerns\LogsJobFailure;
use App\Library\RouletteWheel;
use App\Library\Sending\Lifecycle\AutomationSendLifecycle;
use App\Library\Sending\SendContext;
use App\Library\Sending\SendPipeline;
use App\Model\AutomationEmail;
use App\Model\AutoTrigger;
use App\Model\Campaign;
use App\Model\Customer;
use App\Model\Subscriber;
use App\Model\Subscription;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
/**
* Single-dispatch send job for automation triggers (one trigger action ->
* one email). Sibling to App\Jobs\SendMessage — does NOT inherit from it
* (constructor signatures differ).
*
* The pipeline does the same work as for campaign sends, just with the
* AutomationSendLifecycle hooks: action->setSent on success, action->setError
* on failure, action delay_note + release(600) on rate-limit (no batch path).
*
* Like its sibling, this Job does NOT implement JobControl directly — see
* JobControlAdapter docblock. handle() wraps $this in an adapter for the
* pipeline.
*/
class SendSingleMessage implements ShouldQueue
{
use Batchable;
use Dispatchable;
use InteractsWithQueue;
use LogsJobFailure;
use Queueable;
use SerializesModels;
public $timeout = 900;
public $maxExceptions = 1;
public $failOnTimeout = true;
// Sibling SendMessage carries a Campaign; this single-dispatch job
// carries an AutomationEmail. The pipeline treats both as a "sendable"
// (see SendContext::$campaign docblock).
protected Campaign|AutomationEmail $campaign;
protected Subscriber $subscriber;
protected ?RouletteWheel $servers;
protected ?Subscription $subscription;
protected mixed $autoTriggerId;
protected mixed $actionId;
protected Customer $customer;
public function __construct(
Campaign|AutomationEmail $campaign,
Subscriber $subscriber,
RouletteWheel $servers,
Subscription $subscription = null,
$autoTriggerId = null,
$actionId = null,
) {
$this->campaign = $campaign;
$this->subscriber = $subscriber;
$this->servers = $servers;
$this->subscription = $subscription;
$this->autoTriggerId = $autoTriggerId;
$this->actionId = $actionId;
$this->customer = $campaign->customer;
}
public function retryUntil(): \DateTime
{
return now()->addDays(30);
}
public function handle(): void
{
$this->customer->setUserDbConnection();
$connection = $this->customer->hasLocalDb() ? $this->customer->db_connection : 'mysql';
$trigger = AutoTrigger::on($connection)->find($this->autoTriggerId);
if ($trigger === null) {
throw new \Exception(
"Cannot find trigger {$this->autoTriggerId} (DB connection ".\DB::connection()->getName().')'
);
}
$ctx = new SendContext(
campaign: $this->campaign,
subscriber: $this->subscriber,
servers: $this->servers,
);
$lifecycle = new AutomationSendLifecycle($trigger, $this->actionId, $this->subscription);
// JobControlAdapter bridges this Job's Laravel trait methods to the
// pipeline's strict-typed JobControl interface. See adapter docblock.
$control = new JobControlAdapter($this);
app(SendPipeline::class)->run($ctx, $lifecycle, $control);
}
}