1
0
Fork 0
bill_man/bill_man.py

155 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python3
import logging
from datetime import time, datetime
from util import install_except_hook, KSTTZ, UTCTZ
def handle_daemon(name, action, args):
log = logging.getLogger("main_loop")
from signal import SIGTERM
from util.log import wrap
if action == 'start':
# load config
from util import EnteringLoop
with EnteringLoop(
name,
log_dir=args.log_location,
log_level=args.log_level,
is_forground=args.foreground,
pid_path=args.pid_path
) as loop:
from apscheduler.jobstores.memory import MemoryJobStore
from apscheduler.executors.asyncio import AsyncIOExecutor
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.util import undefined
from signal import SIGTERM, SIGABRT, SIGINT, SIGQUIT
from handler import Session
import ujson
jobstores = {
'default': MemoryJobStore()
}
executors = {
'default': AsyncIOExecutor(),
}
job_defaults = {
'coalesce': True,
'max_instances': 2
}
scheduler = AsyncIOScheduler(
jobstores=jobstores,
executors=executors,
job_defaults=job_defaults,
timezone=KSTTZ,
event_loop=loop)
with open(args.config) as cfgFile:
config = ujson.load(cfgFile)
sess = Session(loop=loop, **config)
del config
job = scheduler.add_job(sess.get_resources,
name="charger",
trigger='cron',
day_of_week='mon-fri',
hour=args.standard_time.hour,
minute=args.standard_time.minute,
second=args.standard_time.second,
args=(args.standard_time,),
next_run_time=datetime.utcnow().replace(tzinfo=UTCTZ).astimezone(
KSTTZ) if args.immediately else undefined
)
scheduler.start()
if not args.immediately:
log.info("job(%s) may be start in %s", job.name, job.next_run_time)
def stopme(*_):
scheduler.shutdown()
sess.close()
log.info("handler closed")
loop.stop()
log.info("loop closed")
loop.add_signal_handler(SIGQUIT, stopme)
loop.add_signal_handler(SIGTERM, stopme)
loop.add_signal_handler(SIGINT, stopme)
loop.add_signal_handler(SIGABRT, stopme)
loop.run_forever()
log.info("bye!")
elif action == 'stop':
from os import path, kill
wrap(name, level=args.log_level, stderr=True)
if not path.exists(args.pid_path):
log.warning("cannot find pidfile(%s)", args.pid_path)
return
with open(args.pid_path, 'r') as pidFile:
pid = int(pidFile.readline())
kill(pid, SIGTERM)
log.warning("pid(%d) sigterm!", pid)
else:
raise NotImplementedError()
if __name__ == '__main__':
import argparse
from functools import partial
install_except_hook()
# 실행 플래그 파싱
parser = argparse.ArgumentParser(
prog='bill_man',
epilog='contact @spi-ca.',
description='report aws billing .',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('--pid_path',
help='specify pidPath',
default='bill_man.pid')
parser.add_argument('--log_level',
help='set logging level',
type=lambda level: logging._nameToLevel[level.upper()],
choices=logging._nameToLevel.keys(),
default='INFO')
parser.set_defaults(func=lambda *_: parser.print_help())
sp = parser.add_subparsers()
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
sp_start.add_argument('--config',
help='specify config file path',
default='bill_man.json')
sp_start.add_argument('--foreground',
help='Don\'t daemonize!',
default=False,
action='store_true')
sp_start.add_argument('--immediately',
help='run batch now!',
default=False,
action='store_true')
sp_start.add_argument('--log_location',
help='specify location of logs!',
default='log')
sp_start.add_argument('--standard_time',
help='set standard time/HHMMSS',
type=lambda ti: time(
hour=int(ti[0:2]),
minute=int(ti[2:4]),
second=int(ti[4:6]),
tzinfo=KSTTZ
),
default='120000')
sp_start.set_defaults(func=partial(handle_daemon, parser.prog, 'start'))
sp_stop = sp.add_parser('stop', help='Stop %(prog)s daemon',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
sp_stop.set_defaults(func=partial(handle_daemon, parser.prog, 'stop'))
args = parser.parse_args()
args.func(args)