2026年8月12日

2026年8月12日

AWS LambdaでServerless関数を作成する方法|WP-Cronを定期実行する関数で手順を学ぶ

AWS Lambda の関数は、「実行ロール(IAM)を用意する → コードを書いてデプロイする → テストしてログを確認する → トリガーをつなぐ」の4段階で作れます。この記事では、題材として「WordPress の WP-Cron を外部から5分おきに起動する関数」を Python で作りながら、各段階で何を決めるのか、どこでつまずきやすいのかを説明します。サーバーを常時動かさずに定期処理を回す、という Lambda の基本的な使い方がひととおり身につきます。

Lambda のランタイムの種類やコンソールの表記は更新されます。この記事の内容は執筆時点(2026年10月現在)のものです。関数を作る際は、コンソールに表示されるサポート中のランタイムから新しいものを選んでください。HTTP エンドポイントとして公開する方法は、API Gateway と組み合わせる別記事で扱います。

なぜWP-Cronを外から起動するのか

WP-Cron は、サイトへのアクセスをきっかけに予約投稿や定期処理を実行する仕組みです。アクセスが少ないサイトでは予約投稿が遅れ、逆にアクセスが多いサイトではページ表示のたびに実行判定が走ります。そこで、アクセス起点の実行を止め、決まった間隔で wp-cron.php を呼び出す方法がよく使われます。サーバーの cron で行うのが一般的ですが、共用サーバーで cron が使いにくい場合や、複数台構成でどのサーバーから呼ぶか決めにくい場合に、Lambda が選択肢になります。

まず wp-config.php の /* That's all, stop editing! */ より上に次の1行を追加し、アクセス起点の実行を止めます。Lambda 側の準備が終わってから追加すると、予約投稿が止まる時間を作らずに済みます。

define( 'DISABLE_WP_CRON', true );

手順1:実行ロールを作る

Lambda 関数は、実行時に「実行ロール」の権限で動きます。今回の関数は外部へ HTTP リクエストを送るだけなので、必要なのは CloudWatch Logs へログを書く権限だけです。AWS 管理ポリシーの AWSLambdaBasicExecutionRole がこの用途に当たります。

コンソールで関数を作る場合は、「基本的な Lambda アクセス権限で新しいロールを作成」に相当する選択肢を選べば自動で作られます。CLI で作る場合は、Lambda が引き受けられるロールを作り、ポリシーを付けます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "lambda.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }
  ]
}
aws iam create-role \
  --role-name wp-cron-lambda-role \
  --assume-role-policy-document file://trust-lambda.json

aws iam attach-role-policy \
  --role-name wp-cron-lambda-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

ロールに不要な権限(S3 のフルアクセスなど)を付けないことが大切です。関数のコードに不具合や脆弱性があった場合、その被害はロールの権限の範囲に及びます。

手順2:関数のコードを書く

Python の標準ライブラリだけで書くと、追加パッケージの同梱が不要になり、デプロイが簡単です。呼び出し先の URL はコードに直接書かず、環境変数で渡します。

# lambda_function.py
import os
import urllib.error
import urllib.request

TARGET_URL = os.environ["TARGET_URL"]  # 例: https://example.com/wp-cron.php
HTTP_TIMEOUT = float(os.environ.get("HTTP_TIMEOUT", "20"))


def lambda_handler(event, context):
    req = urllib.request.Request(
        TARGET_URL + "?doing_wp_cron",
        headers={"User-Agent": "wp-cron-trigger-lambda"},
    )
    try:
        with urllib.request.urlopen(req, timeout=HTTP_TIMEOUT) as res:
            status = res.status
    except urllib.error.HTTPError as e:
        # 4xx/5xx はエラーとして記録し、関数を失敗扱いにする
        print(f"wp-cron returned HTTP {e.code}")
        raise
    except urllib.error.URLError as e:
        print(f"connection failed: {e.reason}")
        raise
    except TimeoutError:
        # wp-cron.php は接続が切れても処理を続けるため、待ち時間切れは警告にとどめる
        print("response timed out; wp-cron may still be running")
        return {"status": "timeout"}

    print(f"wp-cron returned HTTP {status}")
    return {"status": status}

lambda_handler(event, context) が Lambda から呼ばれる入口(ハンドラー)です。ファイル名が lambda_function.py、関数名が lambda_handler なので、ハンドラー設定は lambda_function.lambda_handler になります。ここが食い違うと、実行時に「ハンドラーが見つからない」というエラーになります。

エラーを raise しているのは、失敗を Lambda の「エラー」として数えさせるためです。例外を握りつぶして正常終了させると、CloudWatch のエラー数に表れず、監視で気づけません。

手順3:関数を作成してデプロイする

コンソールでは「関数の作成」から「一から作成」を選び、関数名、ランタイム(Python の新しいバージョン)、実行ロールを指定します。作成後、コードエディターに上のコードを貼り付けてデプロイします。

CLI では、コードを zip にまとめてから作成します。Windows の PowerShell なら Compress-Archive -Path lambda_function.py -DestinationPath function.zip で同じ zip を作れます。

zip function.zip lambda_function.py

aws lambda create-function \
  --function-name wp-cron-trigger \
  --runtime python3.13 \
  --role arn:aws:iam::123456789012:role/wp-cron-lambda-role \
  --handler lambda_function.lambda_handler \
  --zip-file fileb://function.zip \
  --timeout 30 \
  --memory-size 128 \
  --environment "Variables={TARGET_URL=https://example.com/wp-cron.php,HTTP_TIMEOUT=20}"

タイムアウトとメモリの考え方

Lambda の既定のタイムアウトは数秒と短く、HTTP の応答を待つ処理ではすぐに時間切れになります。関数のタイムアウトは、コード内の HTTP タイムアウトより長く設定してください(上の例では 20 秒に対して 30 秒)。メモリは CPU の割り当てとも連動しますが、今回のように待ち時間が中心の処理では最小に近い値で足ります。

ロールを作った直後に create-function を実行すると、ロールの反映待ちで「ロールを引き受けられない」というエラーになることがあります。少し時間を置いて再実行すれば通るのが普通です。

手順4:テスト実行とログの確認

デプロイしたら、手動で一度実行します。

aws lambda invoke --function-name wp-cron-trigger response.json
cat response.json

{"status": 200} が返れば成功です。print の出力は CloudWatch Logs のロググループ /aws/lambda/wp-cron-trigger に記録されます。コンソールの「モニタリング」タブからログへ移動するか、CLI で aws logs tail /aws/lambda/wp-cron-trigger --follow を実行すると確認できます。

うまくいかないときは、次の順に確認すると原因を絞り込めます。

  1. 403 が返る: WAF やセキュリティ系プラグイン、Basic 認証が Lambda からのアクセスを拒否している可能性があります。サーバーのアクセスログで該当リクエストを探します。
  2. 接続エラー: 環境変数の URL の誤り、DNS、サーバー側のファイアウォールを確認します。関数を VPC 内に配置している場合は、NAT ゲートウェイなどインターネットへの経路が必要です。
  3. Task timed out: 関数のタイムアウトがコード内のタイムアウトより短くなっていないか確認します。

手順5:EventBridge Schedulerで5分おきに起動する

定期実行には Amazon EventBridge Scheduler を使います。スケジューラーが Lambda を呼び出すためのロール(scheduler.amazonaws.com が引き受けられ、対象関数への lambda:InvokeFunction だけを許可したもの)を事前に作っておきます。

aws scheduler create-schedule \
  --name wp-cron-every-5min \
  --schedule-expression "rate(5 minutes)" \
  --flexible-time-window Mode=OFF \
  --target '{"Arn":"arn:aws:lambda:ap-northeast-1:123456789012:function:wp-cron-trigger","RoleArn":"arn:aws:iam::123456789012:role/wp-cron-scheduler-role"}'

コンソールの Lambda 画面からトリガーとして EventBridge のルールを追加する方法もあります。どちらでも、設定後に CloudWatch Logs に5分おきの実行記録が並ぶかを確認してください。最後に DISABLE_WP_CRON を有効にし、予約投稿が予定時刻に公開されるかを試せば移行は完了です。

運用中は、Lambda の Errors メトリクスに CloudWatch アラームを設定しておくと、サイト側の障害で WP-Cron が動いていないことに早く気づけます。

まとめ

  • Lambda 関数は「実行ロール → コード → デプロイ → テストとログ → トリガー」の順に作る。
  • 実行ロールは最小権限にし、ログ出力だけなら AWSLambdaBasicExecutionRole で足りる。
  • ハンドラー名、タイムアウト、環境変数は食い違いが起きやすいので、作成時に見直す。
  • 失敗は例外として上げ、CloudWatch のエラー数とアラームで気づける形にする。
  • WP-Cron の外部起動では、Lambda 側の動作確認を済ませてから DISABLE_WP_CRON を有効にする。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲