118 lines
4.5 KiB
Python
118 lines
4.5 KiB
Python
# +======================================================================
|
||
# | 模块: 启动引导层
|
||
# | 说明: 解析命令行参数、创建应用并启动 HTTP 服务,
|
||
# | 注册信号处理实现优雅关闭
|
||
# +======================================================================
|
||
"""启动引导程序。
|
||
|
||
- 解析命令行参数(--port)
|
||
- 创建应用并启动 HTTP 服务
|
||
- 注册信号处理实现优雅关闭
|
||
"""
|
||
|
||
# ----------------------------------------------------------------------
|
||
# 导入依赖
|
||
# 涵盖:信号处理、Tornado HTTP 服务与事件循环、命令行参数工具、
|
||
# 应用/数据库/邮件/Redis 配置、日志器
|
||
# ----------------------------------------------------------------------
|
||
import signal
|
||
|
||
import tornado.httpserver
|
||
import tornado.ioloop
|
||
from tornado.options import define, options, parse_command_line
|
||
|
||
from config.app import TORNADO_ENV, TORNADO_HOST, TORNADO_NAME, TORNADO_PORT
|
||
from config.database import DB_PASSWORD
|
||
from config.email import MAIL_PASSWORD
|
||
from config.redis import REDIS_PASSWORD
|
||
from core.logger import logger
|
||
|
||
# ============================================================
|
||
# 命令行参数定义
|
||
# ============================================================
|
||
define('port', default=TORNADO_PORT, help='run on the given port', type=int)
|
||
|
||
|
||
# ======================================================================
|
||
# 启动 Banner
|
||
# ======================================================================
|
||
_BANNER = r"""
|
||
____ _ _
|
||
| _ \ _ _ __ _ _ __ ___ (_) _ __ __ _ _ __ __| |
|
||
| | | || | | | / _` || '__| / __|| || '_ \ / _` || '__| / _` |
|
||
| |_| || |_| || (_| || | | (__ | || |_) || (_| || | | (_| |
|
||
|____/ \__,_| \__,_||_| \___||_|| .__/ \__,_||_| \__,_|
|
||
|_|
|
||
Tornado + EleVue 企业级管理框架
|
||
"""
|
||
|
||
|
||
# ======================================================================
|
||
# 启动服务
|
||
# ======================================================================
|
||
def main():
|
||
"""启动服务。"""
|
||
# 延迟导入应用工厂,避免与根目录入口模块同名冲突
|
||
from app import create_app
|
||
|
||
# 打印启动 Banner
|
||
print(_BANNER)
|
||
|
||
parse_command_line()
|
||
app = create_app()
|
||
|
||
# 预热 ip2region 离线库,避免首个日志落库时在事件循环上加载阻塞
|
||
try:
|
||
from common.utils.ip2region import preload
|
||
preload()
|
||
except Exception:
|
||
logger.warning("ip2region 预热失败(将延迟到首次查询时加载)")
|
||
|
||
# 生产环境安全提醒(签名密钥已在 config.auth 启动校验中 fail-close;此处对其它
|
||
# 敏感凭据做软告警,提示确认来源,不阻断启动)
|
||
if TORNADO_ENV.strip().lower() == "production":
|
||
for name, value in (("DB_PASSWORD", DB_PASSWORD),
|
||
("REDIS_PASSWORD", REDIS_PASSWORD),
|
||
("MAIL_PASSWORD", MAIL_PASSWORD)):
|
||
if not value:
|
||
logger.warning("生产环境检测到 %s 为空,请确认凭据来源(环境变量 / 密钥管理服务)", name)
|
||
|
||
http_server = tornado.httpserver.HTTPServer(app)
|
||
http_server.listen(options.port)
|
||
|
||
# 启动任务调度器并加载运行中任务
|
||
from modules.job.scheduler import init_scheduler
|
||
init_scheduler()
|
||
|
||
logger.info("服务启动成功 → http://%s:%s", TORNADO_HOST, options.port)
|
||
|
||
ioloop = tornado.ioloop.IOLoop.current()
|
||
|
||
# ============================================================
|
||
# 优雅关闭回调
|
||
# ============================================================
|
||
def _shutdown():
|
||
"""收到退出信号时关闭调度器并停止事件循环。"""
|
||
logger.info("收到退出信号,正在优雅关闭...")
|
||
from modules.job.scheduler import shutdown_scheduler
|
||
shutdown_scheduler()
|
||
ioloop.stop()
|
||
|
||
# ============================================================
|
||
# 注册信号处理(优雅关闭)
|
||
# ============================================================
|
||
for sig in (signal.SIGINT, signal.SIGTERM):
|
||
try:
|
||
signal.signal(sig, lambda s, f: ioloop.add_callback_from_signal(_shutdown))
|
||
except (ValueError, AttributeError, OSError):
|
||
pass
|
||
|
||
ioloop.start()
|
||
|
||
|
||
# ======================================================================
|
||
# 入口
|
||
# ======================================================================
|
||
if __name__ == '__main__':
|
||
main()
|