同期成功

コマンドシグネチャ

php artisan analyzerdb:sync-crawl-success-from-analyzer --data-type=SummaryProduct [--limit=100]
php artisan analyzerdb:sync-crawl-success-from-analyzer --data-type=SummaryProductReview [--limit=100]
php artisan analyzerdb:sync-crawl-success-from-analyzer --data-type=SummaryCategory [--limit=100]
php artisan analyzerdb:sync-crawl-success-from-analyzer --data-type=SummarySearchQuery [--limit=100]

目的

これらのコマンドは、コンソールデータベース(gb_console)のサマリーウィッシュリストテーブルのレコードが、アナライザーデータベース(gb_analyzer)で正常に処理されたかどうかを検証します。適切なタイムスタンプでアナライザーデータベースに一致するレコードが見つかった場合、コンソールデータベースの対応するレコードは「成功」クロールステータスで更新され、両方のデータベース間でデータ処理パイプラインの正確な追跡を維持します。

シーケンス図

メインコマンドフロー

sequenceDiagram
    participant System
    participant Command as analyzerdb:sync-crawl-success-from-analyzer
    participant Repository as SummaryWishlist*Repository
    participant ConsoleDB[(gb_console)]
    participant Logger
    participant Slack
    
    Note over System,Slack: コマンド実行フロー(5分毎)
    
    rect rgb(200, 255, 200)
    Note right of System: 正常ケース - コマンド処理
    
    System->>Command: --data-typeパラメータで実行
    Command->>Logger: パラメータ付きでコマンド開始をログ
    Command->>Repository: chunkDataUpdateCrawlStatusSuccess()
    Repository->>ConsoleDB: crawl_status = Crawlingのレコードをクエリ
    ConsoleDB-->>Repository: 検証が必要なレコードを返す
    Repository-->>Command: レコードのチャンクを返す(最大:limitオプション)
    
    rect rgb(200, 230, 255)
    loop レコードの各チャンクに対して
        Note right of Command: バッチジョブディスパッチ
        Command->>Command: データタイプに基づく専用ジョブをディスパッチ
        Command->>Logger: チャンク処理開始をログ
    end
    end
    
    Command->>Logger: コマンド完了をログ
    Command->>Slack: 処理サマリー通知を送信
    end
    
    rect rgb(255, 200, 200)
    Note right of System: エラーハンドリング
    rect rgb(255, 230, 230)
    alt コマンドエラーが発生
        Command->>Logger: コマンドエラー詳細をログ
        Command->>Slack: エラー通知を送信
    end
    end
    end

SummaryProductジョブフロー

sequenceDiagram
    participant Job as SummaryProductJob
    participant ProductRepo as ProductRepositoryInterface
    participant AnalyzerDB[(gb_analyzer.products)]
    participant ConsoleRepo as SummaryWishlistProductRepository
    participant ConsoleDB[(gb_console.summary_wishlist_products)]
    participant Logger
    participant Slack
    
    Note over Job,Slack: 商品検証ジョブフロー
    
    rect rgb(200, 255, 200)
    Note right of Job: 正常ケース - 商品検証
    
    Job->>Logger: レコード数でジョブ開始をログ
    Job->>Job: レコードからmall_id、input_type、inputを抽出
    Job->>ProductRepo: ルックアップキーで商品をクエリ
    ProductRepo->>AnalyzerDB: mall_id、input_type、inputが一致するSELECT
    Note right of AnalyzerDB: 時間制約:crawl_created_at >= updated_at
    AnalyzerDB-->>ProductRepo: 一致する商品を返す
    ProductRepo-->>Job: 検証済み商品レコードを返す
    
    rect rgb(255, 255, 200)
    alt アナライザーDBで商品が見つかった
        Note right of Job: 成功更新
        Job->>ConsoleRepo: updateByConditions(crawl_status = Success)
        ConsoleRepo->>ConsoleDB: UPDATE crawl_status = 2 WHERE id IN (...)
        ConsoleDB-->>ConsoleRepo: バッチ更新を確認
        ConsoleRepo-->>Job: 更新数を返す
        
        rect rgb(230, 200, 255)
        Note right of Job: 成功監視
        Job->>Logger: 数付きで成功更新をログ
        Job->>Slack: 統計付きで成功通知を送信
        end
    else 一致する商品なし
        Note right of Job: アクション不要
        Job->>Logger: 更新不要をログ
    end
    end
    end
    
    rect rgb(255, 200, 200)
    Note right of Job: エラーハンドリング
    rect rgb(255, 230, 230)
    alt データベースエラーが発生
        Job->>Job: デッドロック/接続エラーを検出
        Job->>Job: 指数バックオフリトライを実装
        Job->>Logger: スリープ時間付きでリトライ試行をログ
        
        rect rgb(233, 196, 196)
        alt 最大リトライ回数超過(5回)
            Job->>Logger: スタックトレース付きで最終エラーをログ
            Job->>Slack: エラー通知を送信
        end
        end
    end
    end
    end

SummaryProductReviewジョブフロー

sequenceDiagram
    participant Job as SummaryProductReviewJob
    participant ReviewRepo as ReviewRepositoryInterface
    participant AnalyzerDB[(gb_analyzer.reviews)]
    participant ConsoleRepo as SummaryWishlistProductReviewRepository
    participant ConsoleDB[(gb_console.summary_wishlist_product_reviews)]
    participant Logger
    participant Slack
    
    Note over Job,Slack: 商品レビュー検証ジョブフロー
    
    rect rgb(200, 255, 200)
    Note right of Job: 正常ケース - レビュー検証
    
    Job->>Logger: レコード数でジョブ開始をログ
    Job->>Job: 関連商品から商品識別子を抽出
    Job->>ReviewRepo: 商品識別子でレビューをクエリ
    ReviewRepo->>AnalyzerDB: mall_id、商品識別子が一致するSELECT
    Note right of AnalyzerDB: 時間制約:crawl_created_at >= updated_at
    AnalyzerDB-->>ReviewRepo: 一致するレビューを返す
    ReviewRepo-->>Job: 検証済みレビューレコードを返す
    
    rect rgb(255, 255, 200)
    alt アナライザーDBでレビューが見つかった
        Note right of Job: 成功更新
        Job->>ConsoleRepo: updateBySummaryWishlistProductIds()
        ConsoleRepo->>ConsoleDB: UPDATE crawl_status = 2 WHERE product_id IN (...)
        ConsoleDB-->>ConsoleRepo: バッチ更新を確認
        ConsoleRepo-->>Job: 更新数を返す
        
        rect rgb(230, 200, 255)
        Note right of Job: 成功監視
        Job->>Logger: 数付きで成功更新をログ
        Job->>Slack: 統計付きで成功通知を送信
        end
    else 一致するレビューなし
        Note right of Job: アクション不要
        Job->>Logger: 更新不要をログ
    end
    end
    end
    
    rect rgb(255, 200, 200)
    Note right of Job: エラーハンドリング
    rect rgb(255, 230, 230)
    alt データベースエラーが発生
        Job->>Job: デッドロック/接続エラーを検出
        Job->>Job: 指数バックオフリトライを実装
        Job->>Logger: スリープ時間付きでリトライ試行をログ
        
        rect rgb(233, 196, 196)
        alt 最大リトライ回数超過(5回)
            Job->>Logger: スタックトレース付きで最終エラーをログ
            Job->>Slack: エラー通知を送信
        end
        end
        end
    end
    end

SummaryCategoryジョブフロー

sequenceDiagram
    participant Job as SummaryCategoryJob
    participant CategoryRepo as TempCategoryRankingRepositoryInterface
    participant AnalyzerDB[(gb_analyzer.t_category_rankings)]
    participant ConsoleRepo as SummaryWishlistCategoryRepository
    participant ConsoleDB[(gb_console.summary_wishlist_categories)]
    participant Logger
    participant Slack
    
    Note over Job,Slack: カテゴリ検証ジョブフロー
    
    rect rgb(200, 255, 200)
    Note right of Job: 正常ケース - カテゴリ検証
    
    Job->>Logger: レコード数でジョブ開始をログ
    Job->>Job: レコードからmall_id、category_idを抽出
    Job->>CategoryRepo: ルックアップキーでカテゴリランキングをクエリ
    CategoryRepo->>AnalyzerDB: mall_id、category_idが一致するSELECT
    Note right of AnalyzerDB: 時間制約:crawl_created_at >= updated_at
    AnalyzerDB-->>CategoryRepo: 一致するカテゴリランキングを返す
    CategoryRepo-->>Job: 検証済みカテゴリレコードを返す
    
    rect rgb(255, 255, 200)
    alt アナライザーDBでカテゴリが見つかった
        Note right of Job: 成功更新
        Job->>ConsoleRepo: updateByConditions(crawl_status = Success)
        ConsoleRepo->>ConsoleDB: UPDATE crawl_status = 2 WHERE id IN (...)
        ConsoleDB-->>ConsoleRepo: バッチ更新を確認
        ConsoleRepo-->>Job: 更新数を返す
        
        rect rgb(230, 200, 255)
        Note right of Job: 成功監視
        Job->>Logger: 数付きで成功更新をログ
        Job->>Slack: 統計付きで成功通知を送信
        end
    else 一致するカテゴリなし
        Note right of Job: アクション不要
        Job->>Logger: 更新不要をログ
    end
    end
    end
    
    rect rgb(255, 200, 200)
    Note right of Job: エラーハンドリング
    rect rgb(255, 230, 230)
    alt データベースエラーが発生
        Job->>Job: デッドロック/接続エラーを検出
        Job->>Job: 指数バックオフリトライを実装
        Job->>Logger: スリープ時間付きでリトライ試行をログ
        
        rect rgb(233, 196, 196)
        alt 最大リトライ回数超過(5回)
            Job->>Logger: スタックトレース付きで最終エラーをログ
            Job->>Slack: エラー通知を送信
        end
        end
    end
    end
    end

SummarySearchQueryジョブフロー

sequenceDiagram
    participant Job as SummarySearchQueryJob
    participant SearchRepo as TempSearchQueryRankingRepositoryInterface
    participant AnalyzerDB[(gb_analyzer.t_sq_rankings)]
    participant ConsoleRepo as SummaryWishlistSearchQueryRepository
    participant ConsoleDB[(gb_console.summary_wishlist_search_queries)]
    participant Logger
    participant Slack
    
    Note over Job,Slack: 検索クエリ検証ジョブフロー
    
    rect rgb(200, 255, 200)
    Note right of Job: 正常ケース - 検索クエリ検証
    
    Job->>Logger: レコード数でジョブ開始をログ
    Job->>Job: レコードからmall_id、keywordを抽出
    Job->>SearchRepo: ルックアップキーで検索クエリランキングをクエリ
    SearchRepo->>AnalyzerDB: mall_id、keywordが一致するSELECT
    Note right of AnalyzerDB: 時間制約:crawl_created_at >= updated_at
    AnalyzerDB-->>SearchRepo: 一致する検索クエリランキングを返す
    SearchRepo-->>Job: 検証済み検索クエリレコードを返す
    
    rect rgb(255, 255, 200)
    alt アナライザーDBで検索クエリが見つかった
        Note right of Job: 成功更新
        Job->>ConsoleRepo: updateByConditions(crawl_status = Success)
        ConsoleRepo->>ConsoleDB: UPDATE crawl_status = 2 WHERE id IN (...)
        ConsoleDB-->>ConsoleRepo: バッチ更新を確認
        ConsoleRepo-->>Job: 更新数を返す
        
        rect rgb(230, 200, 255)
        Note right of Job: 成功監視
        Job->>Logger: 数付きで成功更新をログ
        Job->>Slack: 統計付きで成功通知を送信
        end
    else 一致する検索クエリなし
        Note right of Job: アクション不要
        Job->>Logger: 更新不要をログ
    end
    end
    end
    
    rect rgb(255, 200, 200)
    Note right of Job: エラーハンドリング
    rect rgb(255, 230, 230)
    alt データベースエラーが発生
        Job->>Job: デッドロック/接続エラーを検出
        Job->>Job: 指数バックオフリトライを実装
        Job->>Logger: スリープ時間付きでリトライ試行をログ
        
        rect rgb(233, 196, 196)
        alt 最大リトライ回数超過(5回)
            Job->>Logger: スタックトレース付きで最終エラーをログ
            Job->>Slack: エラー通知を送信
        end
        end
    end
    end
    end

データベーススキーマ

コンソールデータベーステーブル(gb_console)

erDiagram
    summary_wishlist_products {
        bigint id PK
        string input "商品の入力"
        string input_type "入力のタイプ:jan、asin、rakuten_id"
        bigint mall_id FK "mallsテーブルへの外部キー"
        integer crawl_status "クロールのステータス(SummaryProductJobによって更新)"
        timestamp updated_at "時間制約検証に使用"
    }
    
    summary_wishlist_product_reviews {
        bigint id PK
        bigint summary_wishlist_product_id FK "summary_wishlist_productsへの外部キー"
        integer crawl_status "クロールのステータス(SummaryProductReviewJobによって更新)"
        timestamp updated_at "時間制約検証に使用"
    }
    
    summary_wishlist_categories {
        bigint id PK
        string category_id "カテゴリ識別子"
        bigint mall_id FK "mallsテーブルへの外部キー"
        integer crawl_status "クロールのステータス(SummaryCategoryJobによって更新)"
        timestamp updated_at "時間制約検証に使用"
    }
    
    summary_wishlist_search_queries {
        bigint id PK
        bigint mall_id FK "mallsテーブルへの外部キー"
        string keyword "検索キーワード"
        integer crawl_status "クロールのステータス(SummarySearchQueryJobによって更新)"
        timestamp updated_at "時間制約検証に使用"
    }
    
    summary_wishlist_products ||--o| summary_wishlist_product_reviews : "has one"

アナライザーデータベーステーブル(gb_analyzer)

erDiagram
    products {
        bigint id PK
        bigint mall_id FK "モール識別子(ルックアップに使用)"
        string mall_product_id "モールからの商品ID"
        string jan_code "JANコード(null可、ルックアップに使用)"
        string input_type "入力タイプ:asin、jan、rakuten_id(ルックアップに使用)"
        timestamp crawl_created_at "商品がクロールされた時刻(時間制約フィールド)"
    }
    
    reviews {
        bigint id PK
        bigint mall_id FK "モール識別子(ルックアップに使用)"
        string mall_product_id "モールからの商品ID(ルックアップに使用)"
        string jan_code "JANコード(null可、最大50文字、ルックアップに使用)"
        timestamp crawl_created_at "レビューがクロールされた時刻(時間制約フィールド)"
    }
    
    t_category_rankings {
        bigint id PK
        bigint mall_id FK "モール識別子(ルックアップに使用)"
        string category_id "カテゴリ識別子(ルックアップに使用)"
        timestamp crawl_created_at "ランキングがクロールされた時刻(時間制約フィールド)"
    }
    
    t_sq_rankings {
        bigint id PK
        string keyword "検索キーワード(ルックアップに使用、最大100文字)"
        bigint mall_id FK "モール識別子(ルックアップに使用)"
        timestamp crawl_created_at "ランキングがクロールされた時刻(時間制約フィールド)"
    }

検証ルックアップキー

SummaryProduct検証

  • コンソールテーブル: summary_wishlist_products
  • アナライザーテーブル: products
  • ルックアップキー:
    • mall_id(integer)- 完全一致必須
    • input_type(string)- jan、asin、またはrakuten_id
    • input(string)- 実際の商品識別子
  • 時間制約: products.crawl_created_at >= summary_wishlist_products.updated_at
  • 更新フィールド: crawl_status = 2(成功)

SummaryProductReview検証

  • コンソールテーブル: summary_wishlist_product_reviews
  • アナライザーテーブル: reviews
  • ルックアップキー:
    • mall_id(integer)- 関連summary_wishlist_productから
    • 商品識別子 - 関連商品のinput_typeに基づく
  • 時間制約: reviews.crawl_created_at >= summary_wishlist_product_reviews.updated_at
  • 更新フィールド: crawl_status = 2(成功)

SummaryCategory検証

  • コンソールテーブル: summary_wishlist_categories
  • アナライザーテーブル: t_category_rankings
  • ルックアップキー:
    • mall_id(integer)- 完全一致必須
    • category_id(string)- 完全一致必須
  • 時間制約: t_category_rankings.crawl_created_at >= summary_wishlist_categories.updated_at
  • 更新フィールド: crawl_status = 2(成功)

SummarySearchQuery検証

  • コンソールテーブル: summary_wishlist_search_queries
  • アナライザーテーブル: t_sq_rankings
  • ルックアップキー:
    • mall_id(integer)- 完全一致必須
    • keyword(string)- 完全一致必須
  • 時間制約: t_sq_rankings.crawl_created_at >= summary_wishlist_search_queries.updated_at
  • 更新フィールド: crawl_status = 2(成功)

CrawlStatus列挙値

すべてのコンソールテーブルのcrawl_statusフィールドは以下の列挙値を使用します:

  • 0(NotCrawled): 新しいレコードの初期状態
  • 1(Crawling): レコードは現在クローラーによって処理中(同期コマンドによってフィルタリング)
  • 2(Success): 処理が正常に完了(これらのコマンドによって更新)
  • 3(Failed): 処理がエラーで失敗
  • 4(Error): 処理中にシステムエラーが発生

使用されるリポジトリインターフェース

  • SummaryWishlistProductRepositoryInterface: summary_wishlist_products操作を処理
  • SummaryWishlistProductReviewRepositoryInterface: summary_wishlist_product_reviews操作を処理
  • SummaryWishlistCategoryRepositoryInterface: summary_wishlist_categories操作を処理
  • SummaryWishlistSearchQueryRepositoryInterface: summary_wishlist_search_queries操作を処理
  • ProductRepositoryInterface: アナライザーデータベースのproductsテーブルをクエリ
  • ReviewRepositoryInterface: アナライザーデータベースのreviewsテーブルをクエリ
  • TempCategoryRankingRepositoryInterface: アナライザーデータベースのt_category_rankingsテーブルをクエリ
  • TempSearchQueryRankingRepositoryInterface: アナライザーデータベースのt_sq_rankingsテーブルをクエリ

詳細

パラメータ

  • --data-type: 検証するデータのタイプを指定する必須パラメータ
    • SummaryProduct: summary_wishlist_productsテーブルの商品データを検証
    • SummaryProductReview: summary_wishlist_product_reviewsテーブルの商品レビューデータを検証
    • SummaryCategory: summary_wishlist_categoriesテーブルのカテゴリデータを検証
    • SummarySearchQuery: summary_wishlist_search_queriesテーブルの検索クエリデータを検証
  • --limit=N: 処理のバッチサイズを制御するオプションパラメータ(デフォルト:チャンクあたり100レコード)

頻度

各データタイプ(SummaryProduct、SummaryProductReview、SummaryCategory、SummarySearchQuery)に対して5分毎

依存関係

  • コンソールデータベース(gb_console: crawl_status = Crawlingのサマリーウィッシュリストテーブルにレコードが含まれている必要があります
  • アナライザーデータベース(gb_analyzer: 対応するテーブルに処理済みデータが含まれている必要があります:
    • SummaryProduct検証用のproductsテーブル
    • SummaryProductReview検証用のreviewsテーブル
    • SummaryCategory検証用のt_category_rankingsテーブル
    • SummarySearchQuery検証用のt_sq_rankingsテーブル
  • Laravelキューシステム: 非同期ジョブ処理用
  • リポジトリインターフェース: データベース抽象化とバッチ操作用

出力

テーブル

  • summary_wishlist_products: crawl_statusフィールドを2(成功)に更新

    • 更新者: SummaryProductJob
    • ルックアップ方法: mall_idinput_typeinputフィールドに基づく
    • 時間制約: crawl_created_at >= updated_at
  • summary_wishlist_product_reviews: crawl_statusフィールドを2(成功)に更新

    • 更新者: SummaryProductReviewJob
    • ルックアップ方法: 関連商品識別子に基づく
    • 時間制約: crawl_created_at >= updated_at
  • summary_wishlist_categories: crawl_statusフィールドを2(成功)に更新

    • 更新者: SummaryCategoryJob
    • ルックアップ方法: mall_idcategory_idフィールドに基づく
    • 時間制約: crawl_created_at >= updated_at
  • summary_wishlist_search_queries: crawl_statusフィールドを2(成功)に更新

    • 更新者: SummarySearchQueryJob
    • ルックアップ方法: mall_idkeywordフィールドに基づく
    • 時間制約: crawl_created_at >= updated_at

サービス

  • ジョブキュー: 各データタイプの専用検証ジョブをディスパッチ
  • データベーストランザクション: ロールバック機能付きのアトミック更新を保証
  • Slack通知: 処理統計付きの成功/エラー通知を送信
  • ログシステム: タイムスタンプとレコード数付きの詳細実行ログを記録

エラーハンドリング

ログ

システムは監視とデバッグのための包括的なログを生成します:

  • コマンド実行ログ: データタイプとlimitパラメータ付きの開始/終了タイムスタンプ
  • 進捗追跡: 処理されたチャンク数と検証された総レコード数
  • 成功更新: 特定のIDで成功ステータスに更新されたレコード数
  • エラー詳細: ファイル/行情報とリトライ試行付きのデータベースエラー
  • 時間制約違反: タイムスタンプ要件を満たさないレコード

Slack

設定されたSlackチャンネルに自動通知が送信されます:

  • 成功通知: 処理統計(処理レコード数、更新数、実行時間)を含む
  • エラー通知: コンテキストとスタックトレース付きの詳細エラーメッセージを含む
  • リトライ通知: データベースエラーがリトライメカニズムをトリガーした時にアラート
  • 最終失敗アラート: 最大リトライ試行回数を超えた時に送信

トラブルシューティング

データ確認

  1. コンソールデータベースレコードの検証:

    SELECT COUNT(*) FROM summary_wishlist_products WHERE crawl_status = 1; -- クロール中ステータス
    SELECT COUNT(*) FROM summary_wishlist_products WHERE crawl_status = 2; -- 成功ステータス
    
  2. アナライザーデータベース人口の確認:

    SELECT COUNT(*) FROM products WHERE crawl_created_at >= NOW() - INTERVAL 1 HOUR;
    SELECT COUNT(*) FROM reviews WHERE crawl_created_at >= NOW() - INTERVAL 1 HOUR;
    
  3. 時間制約の検証:

    SELECT id, updated_at FROM summary_wishlist_products WHERE crawl_status = 1 ORDER BY updated_at DESC LIMIT 10;
    

ログ確認

  1. Laravelアプリケーションログ: コマンド実行詳細についてstorage/logs/laravel.logを確認
  2. ジョブキューログ: php artisan queue:failedコマンドを使用して失敗したジョブを監視
  3. データベースクエリログ: 遅いまたは失敗するデータベース操作をデバッグするためにクエリログを有効化
  4. Slackメッセージ履歴: エラーパターンと成功率について通知チャンネルを確認

一般的な問題と解決策

  1. データベースデッドロック:

    • 症状: Slackでのリトライ通知
    • 解決策: システムは指数バックオフで自動的にリトライ(最大5回試行)
    • 予防: --limitパラメータでバッチサイズを減らすことを検討
  2. 一致するレコードなし:

    • 症状: クロール中ステータスのレコードがあるにもかかわらずステータス更新なし
    • 解決策: アナライザーデータベースに適切なタイムスタンプの最新データが含まれていることを確認
    • 確認: クローラーとアナライザーシステムが正常に機能していることを確認
  3. 時間制約の問題:

    • 症状: アナライザーデータベースにデータがあるにもかかわらずレコードがクロール中ステータスのまま
    • 解決策: コンソールのupdated_atとアナライザーのcrawl_created_at間のタイムスタンプ整合性を確認
    • 修正: データベース間でシステムクロックが同期されていることを確認
  4. 高処理負荷:

    • 症状: コマンドタイムアウトまたは実行の遅延
    • 解決策: --limit=50またはそれ以下を使用してバッチサイズを減らす
    • 監視: データベースパフォーマンスとキューワーカー容量を確認