1
0

exec.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. """Everything regarding execution of the built app."""
  2. from __future__ import annotations
  3. import os
  4. import platform
  5. import subprocess
  6. from datetime import datetime
  7. from pathlib import Path
  8. from rich import print
  9. from reflex import constants
  10. from reflex.config import get_config
  11. from reflex.utils import console, prerequisites, processes
  12. from reflex.utils.processes import new_process
  13. from reflex.utils.watch import AssetFolderWatch
  14. def start_watching_assets_folder(root):
  15. """Start watching assets folder.
  16. Args:
  17. root: root path of the project.
  18. """
  19. asset_watch = AssetFolderWatch(root)
  20. asset_watch.start()
  21. def run_process_and_launch_url(
  22. run_command: list[str],
  23. loglevel: constants.LogLevel = constants.LogLevel.ERROR,
  24. ):
  25. """Run the process and launch the URL.
  26. Args:
  27. run_command: The command to run.
  28. loglevel: The log level to use.
  29. """
  30. process = new_process(
  31. run_command,
  32. cwd=constants.WEB_DIR,
  33. )
  34. current_time = datetime.now()
  35. if process.stdout:
  36. for line in process.stdout:
  37. if "ready started server on" in line:
  38. url = line.split("url: ")[-1].strip()
  39. print(f"App running at: [bold green]{url}")
  40. if (
  41. "Fast Refresh" in line
  42. or "compiling..." in line
  43. and (datetime.now() - current_time).total_seconds() > 1
  44. ):
  45. current_time = datetime.now()
  46. print(
  47. f"[yellow][Updating App][/yellow] Applying changes and refreshing. Time: {current_time}"
  48. )
  49. elif loglevel == constants.LogLevel.DEBUG:
  50. print(line, end="")
  51. def run_frontend(
  52. root: Path,
  53. port: str,
  54. loglevel: constants.LogLevel = constants.LogLevel.ERROR,
  55. ):
  56. """Run the frontend.
  57. Args:
  58. root: The root path of the project.
  59. port: The port to run the frontend on.
  60. loglevel: The log level to use.
  61. """
  62. # Start watching asset folder.
  63. start_watching_assets_folder(root)
  64. # Run the frontend in development mode.
  65. console.rule("[bold green]App Running")
  66. os.environ["PORT"] = get_config().frontend_port if port is None else port
  67. run_process_and_launch_url(
  68. [prerequisites.get_package_manager(), "run", "dev"], loglevel
  69. )
  70. def run_frontend_prod(
  71. root: Path,
  72. port: str,
  73. loglevel: constants.LogLevel = constants.LogLevel.ERROR,
  74. ):
  75. """Run the frontend.
  76. Args:
  77. root: The root path of the project (to keep same API as run_frontend).
  78. port: The port to run the frontend on.
  79. loglevel: The log level to use.
  80. """
  81. # Set the port.
  82. os.environ["PORT"] = get_config().frontend_port if port is None else port
  83. # Run the frontend in production mode.
  84. console.rule("[bold green]App Running")
  85. run_process_and_launch_url(
  86. [prerequisites.get_package_manager(), "run", "prod"], loglevel
  87. )
  88. def run_backend(
  89. app_name: str,
  90. host: str,
  91. port: int,
  92. loglevel: constants.LogLevel = constants.LogLevel.ERROR,
  93. ):
  94. """Run the backend.
  95. Args:
  96. host: The app host
  97. app_name: The app name.
  98. port: The app port
  99. loglevel: The log level.
  100. """
  101. cmd = [
  102. "uvicorn",
  103. f"{app_name}:{constants.APP_VAR}.{constants.API_VAR}",
  104. "--host",
  105. host,
  106. "--port",
  107. str(port),
  108. "--log-level",
  109. loglevel,
  110. "--reload",
  111. ]
  112. process = new_process(cmd)
  113. try:
  114. process.wait()
  115. except KeyboardInterrupt:
  116. process.terminate()
  117. def run_backend_prod(
  118. app_name: str,
  119. host: str,
  120. port: int,
  121. loglevel: constants.LogLevel = constants.LogLevel.ERROR,
  122. ):
  123. """Run the backend.
  124. Args:
  125. host: The app host
  126. app_name: The app name.
  127. port: The app port
  128. loglevel: The log level.
  129. """
  130. num_workers = processes.get_num_workers()
  131. command = (
  132. [
  133. *constants.RUN_BACKEND_PROD_WINDOWS,
  134. "--host",
  135. host,
  136. "--port",
  137. str(port),
  138. f"{app_name}:{constants.APP_VAR}",
  139. ]
  140. if platform.system() == "Windows"
  141. else [
  142. *constants.RUN_BACKEND_PROD,
  143. "--bind",
  144. f"{host}:{port}",
  145. "--threads",
  146. str(num_workers),
  147. f"{app_name}:{constants.APP_VAR}()",
  148. ]
  149. )
  150. command += [
  151. "--log-level",
  152. loglevel.value,
  153. "--workers",
  154. str(num_workers),
  155. ]
  156. subprocess.run(command)