exec.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. """Everything regarding execution of the built app."""
  2. from __future__ import annotations
  3. import os
  4. import platform
  5. import sys
  6. from pathlib import Path
  7. import uvicorn
  8. from reflex import constants
  9. from reflex.config import get_config
  10. from reflex.utils import console, path_ops, prerequisites, processes
  11. from reflex.utils.watch import AssetFolderWatch
  12. def start_watching_assets_folder(root):
  13. """Start watching assets folder.
  14. Args:
  15. root: root path of the project.
  16. """
  17. asset_watch = AssetFolderWatch(root)
  18. asset_watch.start()
  19. def run_process_and_launch_url(
  20. run_command: list[str],
  21. ):
  22. """Run the process and launch the URL.
  23. Args:
  24. run_command: The command to run.
  25. """
  26. process = processes.new_process(
  27. run_command, cwd=constants.WEB_DIR, shell=constants.IS_WINDOWS
  28. )
  29. if process.stdout:
  30. for line in process.stdout:
  31. if "ready started server on" in line:
  32. url = line.split("url: ")[-1].strip()
  33. console.print(f"App running at: [bold green]{url}")
  34. else:
  35. console.debug(line)
  36. def run_frontend(
  37. root: Path,
  38. port: str,
  39. ):
  40. """Run the frontend.
  41. Args:
  42. root: The root path of the project.
  43. port: The port to run the frontend on.
  44. """
  45. # Start watching asset folder.
  46. start_watching_assets_folder(root)
  47. # Run the frontend in development mode.
  48. console.rule("[bold green]App Running")
  49. os.environ["PORT"] = str(get_config().frontend_port if port is None else port)
  50. run_process_and_launch_url([prerequisites.get_package_manager(), "run", "dev"])
  51. def run_frontend_prod(
  52. root: Path,
  53. port: str,
  54. ):
  55. """Run the frontend.
  56. Args:
  57. root: The root path of the project (to keep same API as run_frontend).
  58. port: The port to run the frontend on.
  59. """
  60. # Set the port.
  61. os.environ["PORT"] = str(get_config().frontend_port if port is None else port)
  62. # Run the frontend in production mode.
  63. console.rule("[bold green]App Running")
  64. run_process_and_launch_url([prerequisites.get_package_manager(), "run", "prod"])
  65. def run_backend(
  66. app_name: str,
  67. host: str,
  68. port: int,
  69. loglevel: constants.LogLevel = constants.LogLevel.ERROR,
  70. ):
  71. """Run the backend.
  72. Args:
  73. host: The app host
  74. app_name: The app name.
  75. port: The app port
  76. loglevel: The log level.
  77. """
  78. uvicorn.run(
  79. app=f"{app_name}:{constants.APP_VAR}.{constants.API_VAR}",
  80. host=host,
  81. port=port,
  82. log_level=loglevel.value,
  83. reload=True,
  84. reload_dirs=[app_name.split(".")[0]],
  85. )
  86. def run_backend_prod(
  87. app_name: str,
  88. host: str,
  89. port: int,
  90. loglevel: constants.LogLevel = constants.LogLevel.ERROR,
  91. ):
  92. """Run the backend.
  93. Args:
  94. host: The app host
  95. app_name: The app name.
  96. port: The app port
  97. loglevel: The log level.
  98. """
  99. num_workers = processes.get_num_workers()
  100. config = get_config()
  101. RUN_BACKEND_PROD = f"gunicorn --worker-class uvicorn.workers.UvicornH11Worker --preload --timeout {config.timeout} --log-level critical".split()
  102. RUN_BACKEND_PROD_WINDOWS = f"uvicorn --timeout-keep-alive {config.timeout}".split()
  103. command = (
  104. [
  105. *RUN_BACKEND_PROD_WINDOWS,
  106. "--host",
  107. host,
  108. "--port",
  109. str(port),
  110. f"{app_name}:{constants.APP_VAR}",
  111. ]
  112. if constants.IS_WINDOWS
  113. else [
  114. *RUN_BACKEND_PROD,
  115. "--bind",
  116. f"{host}:{port}",
  117. "--threads",
  118. str(num_workers),
  119. f"{app_name}:{constants.APP_VAR}()",
  120. ]
  121. )
  122. command += [
  123. "--log-level",
  124. loglevel.value,
  125. "--workers",
  126. str(num_workers),
  127. ]
  128. processes.new_process(command, run=True, show_logs=True)
  129. def output_system_info():
  130. """Show system informations if the loglevel is in DEBUG."""
  131. if console.LOG_LEVEL > constants.LogLevel.DEBUG:
  132. return
  133. config = get_config()
  134. try:
  135. config_file = sys.modules[config.__module__].__file__
  136. except Exception:
  137. config_file = None
  138. console.rule(f"System Info")
  139. console.debug(f"Config file: {config_file!r}")
  140. console.debug(f"Config: {config}")
  141. dependencies = [
  142. f"[Reflex {constants.VERSION} with Python {platform.python_version()} (PATH: {sys.executable})]",
  143. f"[Node {prerequisites.get_node_version()} (Expected: {constants.NODE_VERSION}) (PATH:{constants.NODE_PATH})]",
  144. ]
  145. system = platform.system()
  146. if system != "Windows":
  147. dependencies.extend(
  148. [
  149. f"[NVM {constants.NVM_VERSION} (Expected: {constants.NVM_VERSION}) (PATH: {constants.NVM_PATH})]",
  150. f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.BUN_VERSION}) (PATH: {config.bun_path})]",
  151. ],
  152. )
  153. else:
  154. dependencies.append(
  155. f"[FNM {constants.FNM_VERSION} (Expected: {constants.FNM_VERSION}) (PATH: {constants.FNM_EXE})]",
  156. )
  157. if system == "Linux":
  158. import distro # type: ignore
  159. os_version = distro.name(pretty=True)
  160. else:
  161. os_version = platform.version()
  162. dependencies.append(f"[OS {platform.system()} {os_version}]")
  163. for dep in dependencies:
  164. console.debug(f"{dep}")
  165. console.debug(
  166. f"Using package installer at: {prerequisites.get_install_package_manager()}"
  167. )
  168. console.debug(f"Using package executer at: {prerequisites.get_package_manager()}")
  169. if system != "Windows":
  170. console.debug(f"Unzip path: {path_ops.which('unzip')}")