这是一个网站标题

这是第一个标题

12222222222222222222222222232132132132132132132131232132321

3123333333333323213213

# -*- coding: utf-8 -*-
"""
Flask应用初始化
"""
import atexit
import logging
import os
import signal
import threading

import dotenv
from flask import Flask

dotenv.load_dotenv()
# 导入全局db实例
from models import db
# 注册蓝图
from routes import main_bp, tasks_bp, novels_bp, statistics_bp, health_bp
from routes.chapters import chapter_tasks_bp
from routes.spider import spider_api_bp
from routes.media import media_bp
from utils.task_scheduler import task_scheduler
from tasks.registration import register_all_tasks
from tasks.cron_jobs import setup_cron_jobs
from utils.logger_config import setup_logging


def cleanup_on_exit():
    """应用退出时的清理函数"""
    try:
        # 关闭任务调度器
        if task_scheduler.scheduler.running:
            logger = logging.getLogger(__name__)
            logger.info("正在关闭任务调度器...")
            task_scheduler.shutdown(wait=True)
            logger.info("任务调度器已安全关闭")
    except Exception as e:
        logger = logging.getLogger(__name__)
        logger.exception(f"关闭任务调度器时出错: {str(e)}")


def signal_handler(signum, frame):
    """信号处理器"""
    logger = logging.getLogger(__name__)
    logger.info(f"接收到信号 {signum},开始优雅关闭...")
    cleanup_on_exit()
    os._exit(0)


def create_app(config_name='development'):
    """应用工厂函数"""
    app = Flask(__name__)

    # 导入配置
    from config import config

    # 使用项目专用的日志配置
    log_level = getattr(config, 'log_level', 'DEBUG')  # 开发环境默认DEBUG级别,启用HTTP请求日志
    # 将日志文件放在项目根目录下的 logs 文件夹中,更容易找到
    project_root = os.path.dirname(os.path.abspath(__file__))
    logs_dir = os.path.join(project_root, 'logs')
    os.makedirs(logs_dir, exist_ok=True)
    log_file = os.path.join(logs_dir, 'tweet_engine.log')

    # 使用自定义的日志配置(包含urllib3日志抑制)
    setup_logging(level=log_level, log_file=log_file)

    # 获取应用日志器
    logger = logging.getLogger(__name__)

    # 配置
    app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev-secret-key')

    # MySQL数据库配置
    database_uri = config.database_url
    app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    # 数据库连接信息

    # 导入配置
    from config import MONGO_URI, MONGO_DB_NAME, MONGO_COLLECTION_NAME, REDIS_URL

    # MongoDB配置
    app.config['MONGO_URI'] = MONGO_URI
    app.config['MONGO_DB_NAME'] = MONGO_DB_NAME
    app.config['MONGO_COLLECTION'] = MONGO_COLLECTION_NAME

    # Redis配置(用于缓存)
    app.config['REDIS_URL'] = REDIS_URL

    # 初始化数据库
    db.init_app(app)

    # 注册Web页面blueprints
    app.register_blueprint(main_bp)
    app.register_blueprint(tasks_bp, url_prefix='/tasks')
    app.register_blueprint(novels_bp, url_prefix='/novels')
    app.register_blueprint(statistics_bp, url_prefix='/statistics')
    app.register_blueprint(health_bp, url_prefix='/health')

    # 注册API blueprints(这些blueprints同时包含Web页面和API端点)
    app.register_blueprint(chapter_tasks_bp)  # 章节任务路由
    app.register_blueprint(spider_api_bp, url_prefix='/spider')  # 爬虫路由
    app.register_blueprint(media_bp, url_prefix='/static')  # 媒体文件路由

    # 创建数据库表(处理连接失败的情况)
    try:
        with app.app_context():
            db.create_all()
            # 初始化任务调度器

            if not task_scheduler.scheduler.running:
                # 设置Flask应用引用到task_scheduler
                task_scheduler.set_app(app)
                register_all_tasks()
                task_scheduler.start()

                # 设置定时任务
                setup_cron_jobs(task_scheduler)

    except Exception as e:
        error_msg = str(e)
        logger = logging.getLogger(__name__)
        logger.exception("数据库连接失败: " + error_msg)
        logger.exception("应用将在无数据库模式下运行,部分功能可能受限")

    # 注册退出清理函数(只在主线程中注册)
    if threading.current_thread() is threading.main_thread():
        try:
            # 注册atexit清理函数
            atexit.register(cleanup_on_exit)

            # 注册信号处理器(用于优雅关闭)
            signal.signal(signal.SIGTERM, signal_handler)
            signal.signal(signal.SIGINT, signal_handler)

            logger.info("已注册应用退出清理函数")
        except (ValueError, RuntimeError) as e:
            logger.warning(f"无法注册信号处理器: {str(e)}")

    return app

3213213213213213213

321321321321321321312313213

1 2

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容