実践応用:データ自動収集と通知送信

前章では、様々なスケジューリングの「実行基盤」(Linuxホスト、GitHub Actions、Vercel Cronなど)を学びました。ここではそれらを統合し、実世界で最も一般的なビジネスシナリオである**「日次プッシュ通知システム」**を実装します。

シナリオ説明

「仮想通貨相場日報」システムを構築します。このプログラムは毎朝8時に以下の3つの処理を実行します:

  1. 無料のSupabaseデータベースからサービス登録ユーザー(Line Notifyトークン)を取得
  2. 外部APIを呼び出して最新のビットコイン価格を取得
  3. ループ処理で最新レートをLine Notify経由で全登録者に配信

このスクリプトはGitHub Actionsで実行することも、Next.js APIとしてVercelにデプロイすることも可能です。ここではNode.js(TypeScript)スクリプトを例に説明します。

事前準備

  1. Supabaseデータベースsubscribersテーブルを作成(id(主キー)、line_token(文字列)の2カラム)
  2. Line NotifyLine Notify公式サイトで個人アクセストークンを取得し、Supabaseデータベースに登録

コア実装コード

必要なパッケージをインストール:

npm install @supabase/supabase-js axios

メインスクリプトdaily-job.ts

import { createClient } from '@supabase/supabase-js';
import axios from 'axios';

// ==========================================
// 1. 環境変数設定
// ==========================================
// 本番環境ではprocess.envで読み取り、ハードコーディングしないこと!
const SUPABASE_URL = process.env.SUPABASE_URL || 'https://your-project.supabase.co';
const SUPABASE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY || 'your-service-role-key';

// Supabaseクライアント初期化(RLSを回避するためService Role Key使用)
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);

// ==========================================
// 2. ビットコイン価格取得関数
// ==========================================
async function getBitcoinPrice(): Promise<number | null> {
  try {
    const response = await axios.get('https://api.coindesk.com/v1/bpi/currentprice.json');
    const priceStr = response.data.bpi.USD.rate;
    // 桁区切りカンマを除去し数値変換
    return parseFloat(priceStr.replace(/,/g, ''));
  } catch (error) {
    console.error('価格取得失敗:', error);
    return null;
  }
}

// ==========================================
// 3. Line Notify送信関数
// ==========================================
async function sendLineNotify(token: string, message: string) {
  try {
    await axios.post(
      'https://notify-api.line.me/api/notify',
      `message=${encodeURIComponent(message)}`,
      {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Authorization': `Bearer ${token}`
        }
      }
    );
    console.log('✅ 送信成功');
  } catch (error) {
    console.error('❌ 送信失敗:', error);
  }
}

// ==========================================
// 4. メイン処理(スケジュールジョブ)
// ==========================================
async function runDailyJob() {
  console.log('🚀 ��次タスク実行開始...');

  // ステップA:データ取得
  const price = await getBitcoinPrice();
  if (!price) {
    console.log('価格取得不可、処理中止');
    return;
  }
  
  const message = `\nおはようございます!💰\n本日のビットコイン相場:$${price} USD\n良い投資を!`;
  console.log('送信メッセージ:', message);

  // ステップB:登録者一覧取得
  const { data: subscribers, error } = await supabase
    .from('subscribers')
    .select('line_token');

  if (error || !subscribers) {
    console.error('登録者データ取得エラー:', error);
    return;
  }

  console.log(`登録者数 ${subscribers.length} 名、一斉送信開始...`);

  // ステップC:ループ処理で個別送信
  for (const sub of subscribers) {
    if (sub.line_token) {
      // Lineのレートリミット回避のため遅延処理
      await new Promise(resolve => setTimeout(resolve, 500));
      await sendLineNotify(sub.line_token, message);
    }
  }

  console.log('🎉 日次タスク完了!');
}

// 実行
runDailyJob();

実装上の注意点

本スクリプトをGitHub Actionsやサーバーで運用する際、特に注意すべき3つのポイント:

  1. APIレートリミット: 73行目で示したように、登録者が5人から5000人に増えた場合、Promise.allで5000リクエストを同時送信すると、LineからDDoS攻撃とみなされトークンが永久ブロックされます。ループ内に遅延処理を追加するか、キューシステムの導入が必須です。

  2. SupabaseのService Role Key: スケジュールスクリプトはバックエンドで自動実行されるため、RLSを回避するにはANON_KEYではなくSERVICE_ROLE_KEYが必要です。このキーは絶対にフロントエンドに露出させず、環境変数で管理してください。

  3. エラーハンドリングとリトライ機構: 自動スクリプトは無人状態で実行されます。APIがメンテナンス中の場合、スクリプトはクラッシュします。全てのネットワークリクエストをtry-catchで囲み、失敗時には管理者に通知する仕組みを実装しましょう。

まとめ

おめでとうございます!これで「自動スケジューリング」の核心をマスターしました。基礎的なLinux Crontabから、クラウド時代のGitHub Actions、Vercel Cronまでを網羅し、実際のビジネス価値を生む日次通知システムを構築できました。

これらの技術を組み合わせれば、自動チケット購入システム、データベースバックアップスクリプト、一人運営のメールマガジンプラットフォームなども実現可能です。これこそがプログラミングの真髄です:一度コードを書けば、コンピュータが永遠に働き続けてくれます!

完全なチュートリアルをロック解除

このチャプターは有料コンテンツです。プロジェクトに参加して、10以上の神レベルのPromptや実際のソースコード例を含む、5000字以上の深い分析をロック解除してください!