Cronの時間指定をお客さんに任せたい

に公開

TL;DR

「バックアップの時間を変えてほしい」「監視の間隔を調整したい」...そんなお客さんからの依頼、毎回サーバーにSSHで入ってcrontab -eしてませんか?

もうやめましょう。お客さんに任せましょう。

Go標準ライブラリだけで作ったWebアプリ「go-cron-gate」を使えば、お客さんがブラウザからポチポチするだけでcronの時間設定を変更できます。開発者はもうcronの設定変更から解放されます。

go-cron-gateのメイン画面

お客さんでも使えるシンプルなWebインターフェース

きっかけ:また「cron変えて」って言われた...

普段はWebエンジニアとして開発したり、QAエンジニアとしてテストしたりしています。Goの経験は正直浅くて、簡単なRESTAPIを作ったことがある程度でした。

ある日のこと、お客さんから連絡が来ました。

「すみません、バックアップの時間を夜中の2時から夜10時に変更してもらえますか?」

はい、また来ました。cronの時間変更依頼です。

これで何度目でしょうか。毎回サーバーにSSH接続して、crontab -eして、時間を変更して...。作業自体は数分で終わりますが、この「毎回」が地味にストレスなんですよね。

しかも、お客さんからすれば「ちょっと時間を変えるだけ」のはずなのに、わざわざ連絡して待たなきゃいけない。お互いにとって非効率すぎる。

「これ、お客さんが自分で変更できたら楽なのに...」

そう思ったのが、このプロジェクトの始まりでした。

なぜ「お客さんに任せたい」のか

開発者側の本音

  • 毎回SSH接続するの面倒: たった1行変更するだけなのに...
  • 深夜・休日の対応: 「明日の朝までに変えておいて」が地味にしんどい
  • 優先度の問題: 他の開発作業があるのに時間を取られる
  • コミュニケーションコスト: 要件確認、作業完了報告...

お客さん側の本音(多分)

  • 連絡するのが申し訳ない: こんな簡単なことで...
  • 待たなきゃいけない: すぐ変更したいのに
  • 現状が分からない: 今どんな設定になってるんだっけ?
  • 試行錯誤できない: ちょっと試したいだけなのに毎回依頼...

でも現実は...

「お客さんにSSHとcrontabの知識を求めるのは無理」

これが現実です。crontab -eなんて、エンジニアでも最初は戸惑うもの。お客さんに「0 2 * * *って書いて」なんて言えるわけがありません。

なので、Webインターフェースを作ることにしました。

「お客さんに任せられる」ための工夫

1. 技術用語を徹底的に排除

細かすぎる設定をしない場合はcronの0 2 * * *みたいな謎の記号は一切出てきません。

代わりに:

  • 「毎日」「毎週」「毎月」などの分かりやすいプリセット
  • 時間は普通の時計形式で選択
  • 「有効」「無効」の状態が一目で分かる

お客さんが見るのは、日本語だけです。

2. でも開発者も安心できるセキュリティ

「お客さんに任せる」といっても、野放しにするわけにはいきません。

  • Basic認証で保護: 誰でもアクセスできるわけじゃない
  • 入力値は徹底チェック: 変な設定はそもそも保存できない
  • タイミング攻撃対策済み: セキュリティの基本は押さえてます

お客さんには自由に、でも開発者には安心を。

3. 保守しやすさを最優先

「便利だけどメンテできない」では意味がありません。

  • Go標準ライブラリのみ: npm installとかしなくていい
  • 単一バイナリ: scpで1ファイル送るだけ
  • テストカバレッジ90%+: 今後の機能改修を見据えて

実際にお客さんに任せてみた結果

お客さんの反応

before:

「すみません、バックアップの時間を夜10時に変更してもらえますか?」
(連絡 → 待つ → 確認 → ありがとうございます)

after:

「あ、自分で変えておきました!」
(終わり)

最高

技術的な話:AI(VibeCoding)に頼りまくった

このプロジェクト、ほぼAIが書きました。

Goの経験が浅い私一人では、こんなにちゃんとしたものは作れなかったと思います。でも、VibeCoding(AI支援コーディング)を使うことで、「やりたいこと」を伝えるだけで高品質なコードが生成されました。

使用技術スタック

  • Go 1.21+: メインの開発言語
  • 標準ライブラリのみ: 外部依存を避けてシンプルな構成(本番環境)
  • HTMLテンプレート: サーバーサイドレンダリング
  • Basic認証: セキュアなアクセス制御
  • テスト用依存: github.com/stretchr/testify (テストコード専用)

アーキテクチャ設計

主要コンポーネント

  • カスタムHTTPルーター: http.ServeMuxを使用し、グローバルmuxよりも良い分離を実現
  • 統一的なエラーハンドリング: internal/errorsパッケージによる構造化ログと集中的なエラー処理
  • スレッドセーフな操作: Mutexによるcrontabファイルへの並行アクセス保護
  • 包括的なテスト: 単体テストと統合テストで90%以上のカバレッジ

プロジェクト構成

go-cron-gate/
├── main.go                      # アプリケーションエントリーポイント
├── main_test.go                 # メインアプリケーションの単体テスト
├── internal/
│   ├── auth/
│   │   ├── auth.go             # タイミング攻撃対策付きBasic認証
│   │   └── auth_test.go        # 認証の単体テスト
│   ├── cron/
│   │   ├── service.go          # スレッドセーフなcrontabファイル操作
│   │   ├── service_test.go     # cronサービスの単体テスト
│   │   └── service_bench_test.go # パフォーマンスベンチマークテスト
│   ├── errors/
│   │   ├── errors.go           # 統一的なHTTPエラーハンドリング
│   │   └── errors_test.go      # エラーハンドリングの単体テスト
│   ├── handler/
│   │   ├── handler.go          # HTTPリクエストハンドラ
│   │   └── handler_test.go     # ハンドラの単体テスト
│   └── template/
│       ├── template.go         # 日本語UI対応のHTMLテンプレート
│       └── template_test.go    # テンプレートレンダリングとXSS対策のテスト(26テスト)
├── test/
│   ├── integration_test.go     # エンドツーエンドの統合テスト
│   └── test_crontab.txt        # テスト用サンプルcrontab
└── docs/                        # プロジェクトドキュメント

セキュリティの実装詳細

1. タイミング攻撃対策

// crypto/subtileを使用した定数時間比較
userMatch := subtle.ConstantTimeCompare([]byte(user), []byte(ba.username))
passMatch := subtle.ConstantTimeCompare([]byte(pass), []byte(ba.password))

// 両方の比較を常に実行し、情報漏洩を防ぐ
if (userMatch & passMatch) != 1 {
    ba.unauthorized(w)
    return
}

2. HTTPサーバーの強化

server := &http.Server{
    Addr:           ":" + port,
    Handler:        mux,
    ReadTimeout:    15 * time.Second,
    WriteTimeout:   15 * time.Second,
    IdleTimeout:    60 * time.Second,
    MaxHeaderBytes: 1 << 20, // 1 MB
}

使用方法

1. インストール

# ソースからビルド
git clone https://github.com/0fuzimaru0/GoCronGate.git
cd go-cron-gate
go build -o cron-gate

2. アプリケーションの起動

./cron-gate -port 8080 -cron /var/spool/cron/crontabs/root -user admin -pass secret123

コマンドラインオプション:

  • -port: HTTPサーバーのポート番号(デフォルト: 8080)
  • -cron: crontabファイルのパス(デフォルト: /var/spool/cron/crontabs/root)
  • -user: Basic認証のユーザー名(必須)
  • -pass: Basic認証のパスワード(必須)

3. Webインターフェースへのアクセス

ブラウザで http://localhost:8080 にアクセスし、設定した認証情報でログインします。

4. ローカルテスト用の設定

# テスト用crontabファイルの作成
cat > test_crontab.txt << 'EOF'
# Example crontab for testing
# Run backup every day at 2am
0 2 * * * /usr/local/bin/backup.sh

# Run cleanup every Sunday at 3am
0 3 * * 0 /usr/local/bin/cleanup.sh

# Run monitoring every 5 minutes
*/5 * * * * /usr/local/bin/monitor.sh

# Disabled job
# 0 4 * * * /usr/local/bin/disabled.sh
EOF

# アプリケーションの起動
./cron-gate -port 8081 -cron ./test_crontab.txt -user admin -pass test123

テストと品質保証

プロジェクトには包括的なテストが含まれており、90%以上のテストカバレッジを達成しています。QAエンジニアとしての経験を活かし、以下の観点でテストを設計しました。

テストカバレッジ詳細

パッケージ カバレッジ
auth 100%
cron 95.7%
errors 100%
handler 77.6%
main 90.9%
全体 90%+

テスト戦略

  • 単体テスト: 各コンポーネントの動作確認(26テストケース含む)
  • 統合テスト: エンドツーエンドのワークフロー確認
  • ベンチマークテスト: パフォーマンスの計測と最適化
  • セキュリティテスト: 認証機能とタイミング攻撃対策の動作確認
  • エラーハンドリングテスト: 異常系の動作確認
  • XSS対策テスト: テンプレートエンジンのセキュリティ確認
# テストの実行
go test ./... -v

# カバレッジレポートの生成
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out

# ベンチマークテストの実行
go test -bench=. ./internal/cron/

デプロイと運用

本番環境での運用

systemdサービスとして実行

# /etc/systemd/system/cron-gate.service
[Unit]
Description=Cron Gate Web Manager
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/cron-gate -port 8080 -cron /var/spool/cron/crontabs/root -user admin -pass YOUR_SECURE_PASSWORD
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target
# サービスの有効化と起動
sudo systemctl daemon-reload
sudo systemctl enable cron-gate
sudo systemctl start cron-gate

Nginxとの連携(本番環境推奨)

server {
    listen 443 ssl http2;
    server_name cron.yourdomain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

同じ悩みを持つ人へ

もし「毎回cron変更するの面倒だな...」と思っているなら、このアプリを使ってみてください。

あるいは、自分で似たようなツールを作ってみるのもいいかもしれません。AIの力を借りれば、思ったより簡単に作れます。


リポジトリ: https://github.com/0fuzimaru0/GoCronGate

気になった方は、ぜひスターをください ⭐

同じ悩みを持つ人の助けになれば嬉しいです。

Discussion