TOP

cron脱却(コンテナ化を見据えて)



ホーム > 個人開発したことまとめ > cron脱却

cron脱却(コンテナ化を見据えて)

新しく配属されたプロジェクトで Docker や GitLab で自動リリース機能構築(CD)など、これまで触れたことのない技術が大量にあったので、それらを使用することで少しでも早くその技術に慣れ、使いこなせるようになりたかった。
なので今後コンテナ化、GitLab で CD 機能を構築していくが、その前に cron から脱却し、各言語のスケジューラを使用することでコンテナ化したときの移植性を高めたい。
稼働時間を変えたいとか、新しく bot を作った時の稼働タイミングの設定を、これまで使用していた cron から各アプリで行うように修正することで、ローカルで設定したものを GitLab に push してしまえば後は勝手にリリースされて時間になったら bot が稼働するという状態を目指したい。



どんな仕組み?

対応前



1つ1つのプログラムは別ファイルになっており、それを cron でキックしていた。



対応後

親となるプログラムを作り、そこで稼働時間の設定を行い、時間になったら動くような仕掛けを作った。






Go のスケジューラと実装

jobrunner というライブラリを使用した。

package main
import (
"net/http"
"time"
"gorunner/common"
"gorunner/public_account"
tweetcount "gorunner/tweet_count"
"github.com/bamzi/jobrunner"
)
// MyJob ...
type TweetCount struct{}
type TweetTest struct{}
type PublicAccount struct{}
type Kyomukyomupurin struct{}
func main() {
common.LoadEnv()
time.Local = time.FixedZone("JST", 9*60*60)
jobrunner.Start()
// 稼働時間の設定
jobrunner.Schedule("15 00 * * *", Kyomukyomupurin{})
jobrunner.Schedule("30 00 * * *", TweetCount{})
jobrunner.Schedule("00 08 * * *", PublicAccount{})
// リリース完了通知用
jobrunner.Now(TweetTest{})
}
// Run ...
func (e TweetCount) Run() {
tweetcount.TweetCount(common.IdSagamax)
}
func (e PublicAccount) Run() {
public_account.TweetPublicAccount(common.IdSagamax)
}
func (e Kyomukyomupurin) Run() {
tweetcount.Kyomukyomu(common.IdSagamax)
}
func (e TweetTest) Run() {
tweetcount.TweetCount(common.IdSagamaxTest)
}
view raw jobrunner.go hosted with ❤ by GitHub

python のスケジューラと実装

schedule というライブラリを使用した。

import schedule
import io
import sys
from ikusei_charas import ikuseiCharas, temporary
from regularly_check import dailyCheck
from artist_rt import SagaRsPictures, PixivScraping
from account_info import record_account_info
from time import sleep
from dotenv import load_dotenv
from youtube_regist import youtuberegist
from youtube_upload import youtubeupload
from auto_follow import auto_follow as autoFollow
from os.path import join
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
# 環境変数の読み込み
dotenv_path = join("config", ".env")
load_dotenv(dotenv_path)
# スケジュール登録
# アカウント情報を保存するbot
schedule.every(1).days.at("05:00").do(record_account_info.recordAccInfo)
# youtubeのサガ公式チャンネルに動画がuploadされたことを報知するbot
schedule.every(1).days.at("07:30").do(
youtubeupload.tweetYoutubeUpload, "sagamax")
# youtubeのサガ公式チャンネルの登録者数をカウントするbot
schedule.every(1).days.at("08:00").do(
youtuberegist.tweetYoutubeRegist, "sagamax")
# 育成応援キャンペーンの報知
schedule.every(1).days.at("11:00").do(
ikuseiCharas.tweetIkuseiCampaign, "sagamax_bot2")
schedule.every(1).days.at("19:00").do(
ikuseiCharas.tweetIkuseiCampaign, "sagamax_bot2")
# イベントリマインダー
schedule.every(1).days.at("12:00").do(
dailyCheck.dailyRemind, "sagamax_bot")
schedule.every(1).days.at("20:00").do(
dailyCheck.dailyRemind, "sagamax_bot")
# ロマサガ公式絵の引用RT
schedule.every(3).minutes.do(SagaRsPictures.searchArt, "sagamax")
# インサガpixiv絵をツイート
schedule.every(1).days.at("08:30").do(PixivScraping.pixivSearch, "sagamax")
# イベント実行
while True:
schedule.run_pending()
sleep(1)


参考



ぶつかった壁とか学んだこととか

Go は割とすんなり行けた。

Go の場合
.
├── scheduler.go
└── XXX
    └──XXX1.go

 ⇒scheduler.go で XXX1.go を import してしまえばいい感じに呼び出してくれる。何か間違えていたらコンパイルエラーで教えてくれる。

python はちょっと苦戦。
今までは1つのファイルに全ての処理を書いていたが、 scheduler.py から違うディレクトリにある python プログラムを呼び出す必要があり、その場合の書き方がわからない。


python の場合
.
├── scheduler.py
└── YYY
    └──YYY1.py

 ⇒scheduler.py で YYY1.py を import するだけだとうまくいかない。

python で別ディレクトリのモジュールを呼び出す場合、以下4つのやり方がある。

  • 絶対インポート/相対インポート
  • sys.path.append で対象ファイルのパスを追加
  • 環境変数 PYTHONPATH を設定
  • .pthファイルを作成

絶対インポート/相対インポート

呼び出したいモジュールの相対パスを指定して import する方法。
例:以下のような階層構造の場合。

階層構造
.
├── main.py
└── lib
   ├── liba
   │   └── lib_a.py
   └── libb
       └── lib_b.py


絶対インポート

main.py から lib_a.py を import したい。

main.py
from lib.liba.lib_a import aaa
aaa.funcA()

相対インポート

lib_a.py から、一つ上の階層にある libb を指定したい

lib_a.py
..libb.lib_b import bbb
bbb.funcB()


sys.path.append で対象ファイルのパスを追加

python が import したモジュールを検索するパスは、標準ライブラリのsysモジュールのsys.pathに格納されている。 sys.path は sys.path.append([対象パスの文字列]) で追加できるので、 import 前にこれを実行すれば別ディレクトリでも import 可能。

sys.path.append('lib.liba.lib_a')
from lib_a import aaa
sys.path.append('..libb.lib_b')
from lib_b import bbb


環境変数 PYTHONPATH を設定

環境変数 PYTHONPATH に読み込んでほしいモジュールのパスを追加すると読み込んでくれるようになる。


.pthファイルを作成

site-packages .pthファイルを作成してそこに対象モジュールのパスを書くと読み込んでくれる。



参考