freescout2ant/Console/Commands/ArchiveThreads.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

62 lines
2 KiB
PHP

<?php
namespace Modules\AmeiseModule\Console\Commands;
use App\Thread;
use App\User;
use Illuminate\Console\Command;
use Modules\AmeiseModule\Entities\CrmArchive;
use Modules\AmeiseModule\Entities\CrmArchiveAttempt;
use Modules\AmeiseModule\Entities\CrmArchiveThread;
use Modules\AmeiseModule\Jobs\ArchiveThreadsJob;
class ArchiveThreads extends Command
{
protected $signature = 'ameise:archive-threads';
protected $description = 'Archiviere neue Threads ins CRM für alle Nutzer, die die Konversation archiviert haben';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$conversationIds = CrmArchiveThread::distinct()->pluck('conversation_id')->toArray();
$threadIds = CrmArchiveThread::distinct()->pluck('thread_id')->toArray();
$threads = Thread::select('threads.*')
->where('state', Thread::STATE_PUBLISHED)
->whereNotIn('threads.id', $threadIds)
->whereIn('threads.conversation_id', $conversationIds)
->with(['conversation', 'attachments'])
->get();
$dispatched = 0;
foreach ($threads as $thread) {
$archives = CrmArchive::where('conversation_id', $thread->conversation_id)
->groupBy('archived_by')
->pluck('archived_by')
->toArray();
$users = User::whereIn('id', $archives)->get();
foreach ($users as $user) {
ArchiveThreadsJob::dispatch($thread->conversation, $thread, $user);
$dispatched++;
}
}
$pendingFailures = CrmArchiveAttempt::whereIn('status', CrmArchiveAttempt::FAILURE_STATUSES)
->whereNull('resolved_at')
->count();
$this->info(sprintf(
'ameise:archive-threads dispatched=%d threads=%d unresolved_failures=%d',
$dispatched,
$threads->count(),
$pendingFailures
));
}
}