Compare commits

...

7 Commits

Author SHA1 Message Date
Alek Petuskey
855dc932a6 Comment as public keyt 2024-07-31 14:42:36 -07:00
Alek Petuskey
230474376c Better name for helper 2024-07-31 14:41:50 -07:00
Alek Petuskey
46c6b80e4c more accurate doc string 2024-07-31 14:38:04 -07:00
Alek Petuskey
043f6dce59 test-compile to compile 2024-07-31 14:37:13 -07:00
Alek Petuskey
07f9844cb0 test event to regular event 2024-07-31 14:36:15 -07:00
Alek Petuskey
7d0d72c0df Clean up doc string 2024-07-31 14:34:26 -07:00
Alek Petuskey
05442a4aca Add two metrics to track 2024-07-31 14:04:51 -07:00
5 changed files with 58 additions and 18 deletions

View File

@ -2,6 +2,7 @@
Only the app attribute is explicitly exposed.
"""
import time
from concurrent.futures import ThreadPoolExecutor
from reflex import constants
@ -12,17 +13,17 @@ from reflex.utils.prerequisites import get_app
if constants.CompileVars.APP != "app":
raise AssertionError("unexpected variable name for 'app'")
telemetry.send("compile")
app_module = get_app(reload=False)
app = getattr(app_module, constants.CompileVars.APP)
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
# before compiling the app in a thread to avoid event loop error (REF-2172).
app._apply_decorated_pages()
start_time = time.perf_counter()
compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile)
compile_future.add_done_callback(
# Force background compile errors to print eagerly
lambda f: f.result()
)
compile_future.add_done_callback(lambda f: telemetry.compile_callback(f, start_time))
# Wait for the compile to finish in prod mode to ensure all optional endpoints are mounted.
if is_prod_mode():
compile_future.result()
@ -32,6 +33,5 @@ del app_module
del compile_future
del get_app
del is_prod_mode
del telemetry
del constants
del ThreadPoolExecutor

View File

@ -44,6 +44,7 @@ class Meta(BaseHTML): # Inherits common attributes from BaseHTML
"""Display the meta element."""
tag = "meta"
char_set: Var[Union[str, int, bool]]
content: Var[Union[str, int, bool]]
http_equiv: Var[Union[str, int, bool]]

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import atexit
import os
import time
import webbrowser
from pathlib import Path
from typing import List, Optional
@ -108,8 +109,13 @@ def _init(
raise typer.Exit(2)
template = constants.Templates.DEFAULT
start_time = time.perf_counter()
# Check if the app is already initialized.
reinit = os.path.exists(constants.Config.FILE)
# Initialize the app.
prerequisites.initialize_app(app_name, template)
prerequisites.initialize_app(app_name, template, reinit=reinit)
# If a reflex.build generation hash is available, download the code and apply it to the main module.
if generation_hash:
@ -129,6 +135,10 @@ def _init(
# Finish initializing the app.
console.success(f"Initialized {app_name}")
# Post telemetry event
event_type = "reinit" if reinit else "init"
telemetry.send(event_type, duration=time.perf_counter() - start_time)
@cli.command()
def init(

View File

@ -1419,22 +1419,19 @@ def create_config_init_app_from_remote_template(
shutil.rmtree(unzip_dir)
def initialize_app(app_name: str, template: str | None = None):
def initialize_app(app_name: str, template: str | None = None, reinit: bool = False):
"""Initialize the app either from a remote template or a blank app. If the config file exists, it is considered as reinit.
Args:
app_name: The name of the app.
template: The name of the template to use.
reinit: Whether to reinitialize the app.
Raises:
Exit: If template is directly provided in the command flag and is invalid.
"""
# Local imports to avoid circular imports.
from reflex.utils import telemetry
# Check if the app is already initialized.
if os.path.exists(constants.Config.FILE):
telemetry.send("reinit")
# Check if the app is already initialized. If so, we don't need to init.
if reinit:
return
# Get the available templates
@ -1473,8 +1470,6 @@ def initialize_app(app_name: str, template: str | None = None):
template_url=template_url,
)
telemetry.send("init", template=template)
def initialize_main_module_index_from_generation(app_name: str, generation_hash: str):
"""Overwrite the `index` function in the main module with reflex.build generated code.

View File

@ -4,7 +4,9 @@ from __future__ import annotations
import asyncio
import multiprocessing
import os
import platform
import time
import warnings
try:
@ -82,6 +84,21 @@ def get_memory() -> int:
return 0
def get_page_count(folder: str) -> int:
"""Get the total number of files in a folder.
Args:
folder: The path to the folder.
Returns:
The total number of files in the folder.
"""
total_files = 0
for _, _, filenames in os.walk(folder):
total_files += len(filenames)
return total_files
def _raise_on_missing_project_hash() -> bool:
"""Check if an error should be raised when project hash is missing.
@ -98,6 +115,20 @@ def _raise_on_missing_project_hash() -> bool:
return True
def compile_callback(f, start_time):
"""Callback to send telemetry after compiling the app.
Args:
f: The future object.
start_time: The start time of the compilation.
"""
try:
# Force background compile errors to print eagerly
f.result()
finally:
send("compile", duration=time.perf_counter() - start_time)
def _prepare_event(event: str, **kwargs) -> dict:
"""Prepare the event to be sent to the PostHog server.
@ -128,12 +159,12 @@ def _prepare_event(event: str, **kwargs) -> dict:
cpuinfo = get_cpu_info()
additional_keys = ["template", "context", "detail"]
additional_keys = ["template", "context", "detail", "duration"]
additional_fields = {
key: value for key in additional_keys if (value := kwargs.get(key)) is not None
}
return {
"api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb",
"api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb", # Public API key
"event": event,
"properties": {
"distinct_id": installation_id,
@ -145,6 +176,9 @@ def _prepare_event(event: str, **kwargs) -> dict:
"cpu_count": get_cpu_count(),
"memory": get_memory(),
"cpu_info": dict(cpuinfo) if cpuinfo else {},
"pages_count": get_page_count(".web/pages")
if event == "compile" or event == "run-dev"
else None,
**additional_fields,
},
"timestamp": stamp,