Improvements to mail send job and to reduce the number of failed polls going to the failed job table and improvements to determining downlinks

This commit is contained in:
Deon George 2025-04-17 09:33:32 +10:00
parent 3f0e17e20b
commit 1461647159
3 changed files with 61 additions and 23 deletions

View File

@ -9,6 +9,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\ManuallyFailedException;
use Illuminate\Queue\MaxAttemptsExceededException;
use Illuminate\Queue\Middleware\Skip;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
@ -36,8 +37,10 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
private Address $ao;
private ?Mailer $mo;
// Whether to force poll even if there isnt anything waiting to send
private bool $force = FALSE;
public function __construct(Address $ao,Mailer $mo=NULL)
public function __construct(Address $ao,Mailer $mo=NULL,bool $force=FALSE)
{
$this->ao = $ao->withoutRelations();
$this->mo = $mo?->withoutRelations();
@ -77,14 +80,8 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
/**
* When calling MessageProcess - we assume that the packet is from a valid source
*/
public function handle()
public function handle(): void
{
if (! $this->ao->system->mailer_preferred->count() || ($this->mo && (! $this->ao->system->mailer_preferred->find($this->mo)))) {
$this->fail('Missing mailer details');
return;
}
Log::info(sprintf('%s:- Polling [%s] - attempt [%d]',self::LOGKEY,$this->ao->ftn,$this->attempts()));
$setup = Config::get('setup',Setup::findOrFail(config('app.id')));
@ -144,15 +141,15 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
switch (get_class($exception)) {
case ManuallyFailedException::class:
Log::error(sprintf('%s:! Address Poll failed for [%s] (%s)',self::LOGKEY,$this->ao->ftn,$exception->getMessage()));
break;
exit(0);
case MaxAttemptsExceededException::class:
Log::error(sprintf('%s:! Address Poll was tried too many times for [%s]',self::LOGKEY,$this->ao->ftn));
Notification::route('netmail',$this->ao)->notify(new PollingFailed);
Notification::route('netmail',$this->ao)
->notify(new PollingFailed);
$this->ao->system->autohold = TRUE;
$this->ao->system->save();
exit(0);
default:
@ -160,6 +157,38 @@ class AddressPoll implements ShouldQueue, ShouldBeUnique
}
}
public function middleware(): array
{
return [
// If there are no mailer details, we cant poll
Skip::when(function(): bool {
if (! $this->ao->system->mailer_preferred->count()
// If we specify a mailer, make sure it is preferred by the system
|| ($this->mo && (! $this->ao->system->mailer_preferred->find($this->mo)))) {
Log::error(sprintf('%s:! No mailer details, cannot poll [%s]',self::LOGKEY,$this->ao->ftn));
return TRUE;
}
return FALSE;
}),
// If there is no mail anymore, no need trying
Skip::unless(function(): bool {
if ($this->force
|| ($this->ao->echomailWaitingCount() > 0)
|| ($this->ao->fileWaitingCount() > 0)
|| ($this->ao->netmailWaitingCount() > 0)) {
return TRUE;
}
Log::info(sprintf('%s:/ Nothing waiting - abandoning poll [%s]',self::LOGKEY,$this->ao->ftn));
return FALSE;
}),
];
}
public function uniqueId(): string
{
return $this->ao->id;

View File

@ -15,10 +15,14 @@ class MailSend #implements ShouldQueue
private const LOGKEY = 'JMS';
private bool $mode;
/**
* @param bool $crash Send crash mail only
*/
public function __construct(private ?bool $crash=NULL) {}
public function __construct(?bool $mode=NULL) {
$this->mode = $mode;
}
/**
* Execute the job.
@ -30,6 +34,7 @@ class MailSend #implements ShouldQueue
->HubStats(Carbon::now())
->get()
->transform(function($item) {
// Add the list of queued items to the uplink
if ($x=$item->uplink()) {
$x->uncollected_echomail = $item->uncollected_echomail;
$x->uncollected_netmail = $item->uncollected_netmail;
@ -41,15 +46,13 @@ class MailSend #implements ShouldQueue
return $item;
}
})
->filter(function($item) {
if ($item->system->autohold)
return NULL;
return is_null($this->crash) || ($item->system->pollmode) || ($item->system->pollmode === $this->crash) ? $item : NULL;
});
->filter(fn($item)=>(! $item->system->autohold) // System is not on autohold
&& (is_null($this->mode) // If we didnt specify a poll mode, poll anyway
|| ($item->system->pollmode) // If system poll mode is set to crash
|| ($item->system->pollmode === $this->mode))); // If the sytem poll mode is the same as mode calling this send
foreach ($u->groupBy('ftn') as $oo) {
if (Job::where('queue','poll')->get()->pluck('command.address.id')->search(($x=$oo->first())->id) === FALSE) {
if (! Job::where('queue','poll')->get()->pluck('command.address.id')->contains(($x=$oo->first())->id)) {
Log::info(sprintf('%s:- Polling [%s] - we have mail for [%d] links. (%d Netmail,%d Echomail,%d Files)',
self::LOGKEY,
$x->ftn,

View File

@ -920,12 +920,12 @@ class Address extends Model
// If this system is not marked to default route for this address
if (! $this->is_default_route) {
$children = $this->children()
$downlinks = $this->children()
->push($this);
// We route everything for this domain
} else {
$children = self::select('addresses.*')
$downlinks = self::select('addresses.*')
->join('zones',['zones.id'=>'addresses.zone_id'])
->where('addresses.id','<>',$this->id)
->where('domain_id',$this->zone->domain_id)
@ -936,9 +936,15 @@ class Address extends Model
}
// If there are no children
if (! $children->count())
if (! $downlinks->count())
return new Collection;
// Exclude any children of our addresses
$downlinks = $downlinks
->diff(($x=our_address($this->zone->domain,FALSE))
->flatMap(fn($item)=>$item->children())
->merge($x));
// Exclude links and their children.
$exclude = collect();
foreach (our_nodes($this->zone->domain)->diff([$this]) as $o) {
@ -951,7 +957,7 @@ class Address extends Model
$exclude->push($o);
}
return $children->diff($exclude);
return $downlinks->diff($exclude);
}
/**