From 2409c818eea35391475f0faa0f2de7664a73bb0a Mon Sep 17 00:00:00 2001 From: myrmidex Date: Thu, 3 Jul 2025 21:16:22 +0200 Subject: [PATCH] Fix queue issues --- app/Events/ArticleReadyToPublish.php | 2 +- app/Jobs/RefreshArticlesJob.php | 32 +++++++++++++++++++++++++ app/Jobs/SyncChannelPostsJob.php | 15 ++++++++++-- app/Listeners/PublishArticle.php | 19 +++++++++++++-- app/Listeners/ValidateArticle.php | 20 +++++++++++++++- app/Models/Article.php | 1 + app/Providers/AppServiceProvider.php | 9 ------- app/Services/Article/ArticleFetcher.php | 10 +++++++- config/lemmy.php | 1 + docker/entrypoint.sh | 4 ++-- 10 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 app/Jobs/RefreshArticlesJob.php diff --git a/app/Events/ArticleReadyToPublish.php b/app/Events/ArticleReadyToPublish.php index a23ca5c..9bcb7a7 100644 --- a/app/Events/ArticleReadyToPublish.php +++ b/app/Events/ArticleReadyToPublish.php @@ -15,4 +15,4 @@ public function __construct(public Article $article) { } -} \ No newline at end of file +} diff --git a/app/Jobs/RefreshArticlesJob.php b/app/Jobs/RefreshArticlesJob.php new file mode 100644 index 0000000..a618d68 --- /dev/null +++ b/app/Jobs/RefreshArticlesJob.php @@ -0,0 +1,32 @@ +onQueue('lemmy-posts'); + } + + /** + * Execute the job. + */ + public function handle(): void + { + echo "Starting article refresh job...\n"; + + // Call the article refresh command + \Artisan::call('article:refresh'); + + echo "Article refresh job completed!\n"; + } +} diff --git a/app/Jobs/SyncChannelPostsJob.php b/app/Jobs/SyncChannelPostsJob.php index 014934d..1b5a9ea 100644 --- a/app/Jobs/SyncChannelPostsJob.php +++ b/app/Jobs/SyncChannelPostsJob.php @@ -27,7 +27,9 @@ public static function dispatchForLemmy(): void $communityId = config('lemmy.community_id'); $communityName = config('lemmy.community'); - if ($communityId && $communityName) { + if ($communityName) { + // Use a placeholder ID if community_id is not set - we'll resolve it in the job + $communityId = $communityId ?: 'resolve_from_name'; self::dispatch(PlatformEnum::LEMMY, (string) $communityId, $communityName); } else { logger()->warning('Cannot dispatch Lemmy sync job: missing community configuration'); @@ -36,9 +38,13 @@ public static function dispatchForLemmy(): void public function handle(): void { + echo "Starting channel posts sync job...\n"; + if ($this->platform === PlatformEnum::LEMMY) { $this->syncLemmyChannelPosts(); } + + echo "Channel posts sync job completed!\n"; } private function syncLemmyChannelPosts(): void @@ -47,7 +53,12 @@ private function syncLemmyChannelPosts(): void $api = new LemmyApiService(config('lemmy.instance')); $token = $this->getAuthToken($api); - $api->syncChannelPosts($token, (int) $this->channelId, $this->channelName); + // Resolve community ID if it's a placeholder + $communityId = $this->channelId === 'resolve_from_name' + ? $api->getCommunityId($this->channelName) + : (int) $this->channelId; + + $api->syncChannelPosts($token, $communityId, $this->channelName); logger()->info('Channel posts synced successfully', [ 'platform' => $this->platform->value, diff --git a/app/Listeners/PublishArticle.php b/app/Listeners/PublishArticle.php index 86d703f..fda4452 100644 --- a/app/Listeners/PublishArticle.php +++ b/app/Listeners/PublishArticle.php @@ -4,9 +4,15 @@ use App\Events\ArticleReadyToPublish; use App\Jobs\PublishToLemmyJob; +use Illuminate\Contracts\Queue\ShouldQueue; -class PublishArticle +class PublishArticle implements ShouldQueue { + public string|null $queue = 'default'; + public int $delay = 300; + public int $tries = 3; + public int $backoff = 300; + public function __construct() { } @@ -15,11 +21,20 @@ public function handle(ArticleReadyToPublish $event): void { $article = $event->article; + // Check if already published to avoid duplicate jobs + if ($article->articlePublication()->exists()) { + logger()->info('Article already published, skipping job dispatch', [ + 'article_id' => $article->id, + 'url' => $article->url + ]); + return; + } + logger()->info('Article queued for publishing to Lemmy', [ 'article_id' => $article->id, 'url' => $article->url ]); - + PublishToLemmyJob::dispatch($article); } } diff --git a/app/Listeners/ValidateArticle.php b/app/Listeners/ValidateArticle.php index 5048a03..c71403b 100644 --- a/app/Listeners/ValidateArticle.php +++ b/app/Listeners/ValidateArticle.php @@ -5,9 +5,12 @@ use App\Events\ArticleFetched; use App\Events\ArticleReadyToPublish; use App\Services\Article\ValidationService; +use Illuminate\Contracts\Queue\ShouldQueue; -class ValidateArticle +class ValidateArticle implements ShouldQueue { + public string|null $queue = 'default'; + public function __construct() {} @@ -15,13 +18,28 @@ public function handle(ArticleFetched $event): void { $article = $event->article; + // Skip if already validated if (! is_null($article->validated_at)) { + // Even if validated, don't fire ready-to-publish if already has publication + if ($article->isValid() && !$article->articlePublication()->exists()) { + event(new ArticleReadyToPublish($article)); + } + return; + } + + // Skip if already has publication (prevents duplicate processing) + if ($article->articlePublication()->exists()) { return; } $article = ValidationService::validate($article); if ($article->isValid()) { + // Double-check publication doesn't exist (race condition protection) + if ($article->articlePublication()->exists()) { + return; + } + event(new ArticleReadyToPublish($article)); } } diff --git a/app/Models/Article.php b/app/Models/Article.php index 6596ac9..9d4f9c7 100644 --- a/app/Models/Article.php +++ b/app/Models/Article.php @@ -73,6 +73,7 @@ public function articlePublications(): HasMany protected static function booted(): void { static::created(function ($article) { + echo "Article::created event fired for article ID {$article->id}\n"; event(new ArticleFetched($article)); }); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index e9dcdba..34bbef2 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -23,15 +23,6 @@ public function register(): void public function boot(): void { - Event::listen( - ArticleFetched::class, - ValidateArticle::class, - ); - - Event::listen( - ArticleReadyToPublish::class, - PublishArticle::class, - ); Event::listen( ExceptionOccurred::class, diff --git a/app/Services/Article/ArticleFetcher.php b/app/Services/Article/ArticleFetcher.php index d32c04d..011acaa 100644 --- a/app/Services/Article/ArticleFetcher.php +++ b/app/Services/Article/ArticleFetcher.php @@ -51,6 +51,14 @@ public static function fetchArticleData(Article $article): array private static function saveArticle(string $url): Article { - return Article::firstOrCreate(['url' => $url]); + $existingArticle = Article::where('url', $url)->first(); + + if ($existingArticle) { + echo "ArticleFetcher: Found existing article ID {$existingArticle->id} for URL: {$url}\n"; + return $existingArticle; + } + + echo "ArticleFetcher: Creating new article for URL: {$url}\n"; + return Article::create(['url' => $url]); } } diff --git a/config/lemmy.php b/config/lemmy.php index 49b3fc5..23d71d0 100644 --- a/config/lemmy.php +++ b/config/lemmy.php @@ -5,4 +5,5 @@ 'password' => env('LEMMY_PASSWORD'), 'instance' => env('LEMMY_INSTANCE'), 'community' => env('LEMMY_COMMUNITY'), + 'community_id' => env('LEMMY_COMMUNITY_ID'), ]; diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index efc7cbd..7dc7a65 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -48,8 +48,8 @@ elif [ "$1" = "queue" ]; then echo "Dispatching initial sync job..." php artisan tinker --execute="App\\Jobs\\SyncChannelPostsJob::dispatchForLemmy();" - echo "Fetching initial articles..." - php artisan article:refresh + echo "Dispatching article refresh job..." + php artisan tinker --execute="App\\Jobs\\RefreshArticlesJob::dispatch();" fi # Execute the command based on the argument