logo hsb.horse
← ブログ一覧に戻る

ブログ

PM2でCronジョブを作成する: launchdの代替として

macOSでlaunchdの代わりにPM2を使ってCronジョブを作成する方法。設定ファイルとBunを使った定期実行の実装例を整理。

公開日:

macOSで定期実行系の処理を行いたいが、相変わらずlaunchdの設定は分かりづらく、楽をしたかったので、PM2を使うことにした。

PM2でCronジョブとして動か すための設定

Terminal window
cd $PROJECT_ROOT
pm2 ecosystem

ecosystem.config.cjsで設定を管理する。

module.exports = {
apps: [
{
name: "cronJob",
script: "main.ts",
interpreter: "~/.bun/bin/bun",
// インスタンス数は1
instances: 1,
// 15分ごとに起動
cron_restart: "*/15 * * * *",
exec_mode: "fork",
// 対象ファイルが更新されたときに自動再起動するか: しない
watch: false,
// 自動再起動するか: しない
autorestart: false,
},
],
};

ポイント

  • cron_restart: Cron形式で実行間隔を指定
  • autorestart: false: Cronジョブとして実行するため、自動再起動は無効化
  • interpreter: Bunなど任意のランタイムを指定可能

起動コマンド:

Terminal window
pm2 start ecosystem.config.cjs
pm2 save

実行ジョブのサンプル実装

IPアドレスを定期的に取得してDBに格納する処理。

import { Database } from 'bun:sqlite';
const DDL = `CREATE TABLE IF NOT EXISTS ip_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);`
async function fetchIpConfig() {
const response = await fetch("https://ifconfig.io/ip").catch((err) => new Error(err));
if (response instanceof Error || !response.ok) {
return null;
}
const ip = await response.text();
return ip;
}
async function main() {
const ip = await fetchIpConfig();
if (ip == null) return;
using db = new Database('ip-monitor.sqlite', { create: true });
db.exec(DDL);
using query = db.query("INSERT INTO ip_history (ip) VALUES ($ip);");
query.run({ $ip: ip });
}
await main();

参考資料

まとめ

PM2を使えば、launchdよりも簡潔な設定でCronジョブを管理できる。

ecosystem.config.cjsでジョブを定義し、PM2のプロセス管理機能を活用することで、ログ確認や再起動も簡単に行える。