freescout2ant/Jobs/ArchiveThreadsJob.php
Claude 3c3a092f7a
Track failed Ameise archive attempts and add retry tooling
Previously a thread could be skipped silently in ConversationArchiver
(no customer match, ambiguous match, API/network error, attachment
failure) without any record. Default-off logging hid the cause, and the
queue job swallowed exceptions, so messages "archived" in FreeScout
never surfaced as missing in Ameise.

Now every archive attempt records a row in the new crm_archive_attempts
table with status, sanitized HTTP response, attempt counter and
resolution timestamp. ArchiveThreadsJob retries transient failures up to
5 times with exponential backoff; ameise:list-failed-archives and
ameise:retry-failed-archives expose the queue from the CLI; the Ameise
settings page lists open failures with retry/dismiss buttons.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VU73s4KM5JZqVWQYPpK3cP
2026-06-16 23:06:49 +00:00

64 lines
2.3 KiB
PHP

<?php
namespace Modules\AmeiseModule\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Modules\AmeiseModule\Entities\CrmArchiveAttempt;
class ArchiveThreadsJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $thread;
protected $conversation;
protected $user;
public $timeout = 120;
public $tries = 5;
public function __construct($conversation, $thread, $user)
{
$this->conversation = $conversation;
$this->thread = $thread;
$this->user = $user;
}
public function backoff(): array
{
return [60, 300, 900, 3600, 14400];
}
public function handle()
{
config('ameisemodule.ameise_log_status') && \Helper::log('Ameise Cron Log', 'Job Dispatched For Thread ID: '.$this->thread->id.' Conversation ID: '.$this->conversation->id.' User ID: '.$this->user->id.'');
try {
$tokenService = new \Modules\AmeiseModule\Services\TokenService('', $this->user->id);
$apiClient = new \Modules\AmeiseModule\Services\CrmApiClient($tokenService);
$archiver = new \Modules\AmeiseModule\Services\ConversationArchiver($apiClient);
$archiver->archiveConversationData($this->conversation, $this->thread, $this->user);
} catch (\Throwable $e) {
CrmArchiveAttempt::record([
'conversation_id' => $this->conversation->id ?? null,
'thread_id' => $this->thread->id ?? null,
'user_id' => $this->user->id ?? null,
'status' => CrmArchiveAttempt::STATUS_FAILED_EXCEPTION,
'reason' => substr($e->getMessage(), 0, 1000),
]);
throw $e;
}
}
public function failed(\Throwable $e)
{
CrmArchiveAttempt::record([
'conversation_id' => $this->conversation->id ?? null,
'thread_id' => $this->thread->id ?? null,
'user_id' => $this->user->id ?? null,
'status' => CrmArchiveAttempt::STATUS_FAILED_EXCEPTION,
'reason' => 'Final failure after ' . $this->tries . ' attempts: ' . substr($e->getMessage(), 0, 1000),
]);
}
}