main.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import argparse
  2. import logging
  3. import os
  4. import sys
  5. import time
  6. import django
  7. from django.core import management
  8. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  9. APP_DIR = os.path.join(BASE_DIR, 'apps')
  10. os.chdir(BASE_DIR)
  11. sys.path.insert(0, APP_DIR)
  12. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "maxkb.settings")
  13. def collect_static():
  14. """
  15. 收集静态文件到指定目录
  16. 本项目主要是将前端vue/dist的前端项目放到静态目录下面
  17. :return:
  18. """
  19. logging.info("Collect static files")
  20. try:
  21. management.call_command('collectstatic', '--no-input', '-c', verbosity=0, interactive=False)
  22. logging.info("Collect static files done")
  23. except:
  24. pass
  25. def perform_db_migrate():
  26. """
  27. 初始化数据库表
  28. wait-for-it 仅检测 TCP 端口,PostgreSQL 崩溃恢复期间端口已开放但拒绝查询,
  29. 因此在此处增加重试逻辑,等待数据库真正就绪后再执行 migrate。
  30. """
  31. logging.info("Check database structure change ...")
  32. logging.info("Migrate model change to database ...")
  33. max_retries = 10
  34. retry_interval = 5 # seconds
  35. for attempt in range(1, max_retries + 1):
  36. try:
  37. management.call_command('migrate')
  38. return
  39. except Exception as e:
  40. err_msg = str(e)
  41. # 判断是否为数据库仍在启动中(崩溃恢复场景)
  42. is_db_starting = (
  43. 'the database system is starting up' in err_msg
  44. or 'starting up' in err_msg
  45. or 'Connection refused' in err_msg
  46. )
  47. if is_db_starting and attempt < max_retries:
  48. logging.warning(
  49. f'Database is not ready yet (attempt {attempt}/{max_retries}), '
  50. f'retrying in {retry_interval}s... Error: {err_msg}'
  51. )
  52. time.sleep(retry_interval)
  53. else:
  54. logging.error('Perform migrate failed, exit', exc_info=True)
  55. sys.exit(11)
  56. def start_services():
  57. services = args.services if isinstance(args.services, list) else [args.services]
  58. start_args = []
  59. if args.daemon:
  60. start_args.append('--daemon')
  61. if args.force:
  62. start_args.append('--force')
  63. if args.worker:
  64. start_args.extend(['--worker', str(args.worker)])
  65. else:
  66. worker = os.environ.get('MAXKB_CORE_WORKER')
  67. if isinstance(worker, str) and worker.isdigit():
  68. start_args.extend(['--worker', worker])
  69. try:
  70. management.call_command(action, *services, *start_args)
  71. except KeyboardInterrupt:
  72. logging.info('Cancel ...')
  73. time.sleep(2)
  74. except Exception as exc:
  75. logging.error("Start service error {}: {}".format(services, exc))
  76. time.sleep(2)
  77. def dev():
  78. services = args.services if isinstance(args.services, list) else args.services
  79. if services.__contains__('web'):
  80. management.call_command('runserver', "0.0.0.0:8080")
  81. elif services.__contains__('celery'):
  82. management.call_command('celery', 'celery')
  83. elif services.__contains__('local_model'):
  84. from maxkb.const import CONFIG
  85. bind = f'{CONFIG.get("LOCAL_MODEL_HOST")}:{CONFIG.get("LOCAL_MODEL_PORT")}'
  86. management.call_command('runserver', bind)
  87. if __name__ == '__main__':
  88. os.environ['HF_HOME'] = '/opt/maxkb-app/model/base'
  89. os.environ['TMPDIR'] = '/opt/maxkb-app/tmp'
  90. parser = argparse.ArgumentParser(
  91. description="""
  92. qabot service control tools;
  93. Example: \r\n
  94. %(prog)s start all -d;
  95. """
  96. )
  97. parser.add_argument(
  98. 'action', type=str,
  99. choices=("start", "dev", "upgrade_db", "collect_static"),
  100. help="Action to run"
  101. )
  102. args, e = parser.parse_known_args()
  103. parser.add_argument(
  104. "services", type=str, default='all' if args.action == 'start' else 'web', nargs="*",
  105. choices=("all", "web", "task") if args.action == 'start' else ("web", "celery", 'local_model'),
  106. help="The service to start",
  107. )
  108. parser.add_argument('-d', '--daemon', nargs="?", const=True)
  109. parser.add_argument('-w', '--worker', type=int, nargs="?")
  110. parser.add_argument('-f', '--force', nargs="?", const=True)
  111. args = parser.parse_args()
  112. action = args.action
  113. services = args.services if isinstance(args.services, list) else args.services
  114. if services.__contains__('web'):
  115. os.environ.setdefault('SERVER_NAME', 'web')
  116. elif services.__contains__('local_model'):
  117. os.environ.setdefault('SERVER_NAME', 'local_model')
  118. django.setup()
  119. if action == "upgrade_db":
  120. perform_db_migrate()
  121. elif action == "collect_static":
  122. collect_static()
  123. elif action == 'dev':
  124. collect_static()
  125. perform_db_migrate()
  126. dev()
  127. else:
  128. collect_static()
  129. perform_db_migrate()
  130. start_services()