mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 12:26:01 +08:00
* feat: add enhanced Langflow Locust load testing file with user behavior simulations * fix: resolve ruff linting errors in Locust test files - Remove shebang lines from locust files to fix EXE001 errors - Fix docstring formatting (D205) by adding blank lines after summary - Remove unused function arguments (ARG001) by prefixing with underscore - Add noqa comments for acceptable use of random module (S311) - Move imports to top of file to fix E402 * feat: add enhanced load testing targets with improved error handling and reporting options * fix: update locustfile references to use the correct filename for load testing * fix: add error handling for 404 responses in BaseLangflowUser requests * fix: add missing color definition for yellow in Makefile * fix: improve request handling in locustfile for better error reporting - Refactor on_request function parameters for clarity. - Implement strict checking for success in response payload. - Enhance failure messages to include success status for better debugging. * fix: enhance request tracking and error reporting in locustfile - Refactor on_request function to improve environment handling. - Implement strict checks for success in response payloads. - Update failure messages to include success status for better clarity. * fix: remove unnecessary shape parameter from ramp load test command in Makefile - Simplified the command for generating HTML reports and running headless tests by removing the shape parameter, ensuring cleaner execution. * refactor: Clean up import statements across various test files - Removed unnecessary blank lines and organized import statements for consistency. - Ensured that all imports are correctly formatted and follow the project's style guidelines. - Improved readability and maintainability of the test files by standardizing import practices. * chore: Update Ruff configuration for locust tests - Added specific linting rules to the Ruff configuration for locust test files to accommodate common CLI practices. - Included exceptions for missing docstrings, print statements, subprocess calls, and other relevant patterns to enhance code quality while maintaining usability in CLI contexts. - Improved overall maintainability and clarity of the testing codebase by aligning linting rules with project requirements. * refactor: Clean up and organize import statements in test files - Removed unnecessary blank lines and organized imports for consistency across various test files. - Improved readability and maintainability by standardizing import practices. - Ensured that all imports are correctly formatted and follow the project's style guidelines. * feat: Implement comprehensive load testing for Langflow API - Added a detailed locustfile for Langflow API load testing, including multiple user behaviors and performance analysis. - Introduced realistic message distributions and enhanced error logging mechanisms. - Implemented various load test shapes (RampToHundred, StepRamp) to simulate different user loads. - Improved error handling and logging for better diagnostics during tests. - Captured Langflow server logs and provided a summary of errors encountered during testing. - Ensured environment variable configurations for flexibility in testing scenarios. * refactor: rename lfx locust files * feat: Introduce a new Langflow API load testing framework - Added a comprehensive locustfile for Langflow API load testing, replacing the previous locustfile. - Implemented multiple user behaviors and performance analysis with realistic message distributions. - Enhanced error logging and metrics tracking for improved diagnostics during tests. - Introduced various load test shapes (RampToHundred, StepRamp) to simulate different user loads. - Captured Langflow server logs and provided detailed error summaries for better analysis. - Configured environment variables for flexible testing scenarios. * feat: Add Langflow load test setup and runner scripts - Introduced `langflow_run_load_test.py` for executing load tests with customizable parameters and automatic Langflow server management. - Added `langflow_setup_test.py` to facilitate the setup of a Langflow test environment, including user account creation and API key generation. - Implemented interactive flow selection and error handling for a smoother user experience. - Enhanced documentation with usage examples and detailed descriptions for both scripts. * feat: Add example Langflow load testing workflow script - Introduced `langflow_example_workflow.py` to demonstrate a complete workflow for setting up and executing Langflow load tests. - Implemented dependency checks, user prompts, and environment variable management for a seamless testing experience. - Enhanced documentation within the script to guide users through the load testing process and available options. * feat: Add comprehensive README for Langflow load testing - Introduced a detailed README.md for the Langflow load testing framework using Locust. - Documented setup processes, user types, load test shapes, and performance grading. - Included quick start instructions, advanced usage scenarios, and troubleshooting tips. - Enhanced clarity and usability for users looking to implement load testing for Langflow and LFX APIs. * feat: Enhance load testing capabilities in Makefile - Added new load testing commands for enhanced functionality, including setup, execution, and cleanup for Langflow load tests. - Introduced commands for quick and stress testing, as well as listing available flows and running complete workflows. - Updated existing commands to use new locust files for improved performance and reporting. - Enhanced documentation within the Makefile to guide users through the new load testing features and options. * feat: Enhance Langflow load test scripts with improved host handling - Updated argument parsing to clarify the use of the `--host` option, including guidance for remote instances. - Added checks for remote host detection and provided user feedback on starting Langflow. - Enhanced health check messages to specify accessibility of the Langflow instance. - Improved documentation within the scripts to assist users in configuring and running load tests effectively. * docs: Expand README for remote instance load testing - Added a new section detailing the setup and execution of load tests against remote Langflow instances. - Included important notes on best practices for remote testing, such as using HTTPS and monitoring resources. - Updated examples to reflect remote instance configurations, enhancing clarity for users conducting load tests in varied environments. * feat: Improve API project fetching with enhanced error handling and response validation - Updated the `get_starter_projects_from_api` function to ensure proper URL formatting and added detailed logging for request status. - Implemented fallback logic to attempt fetching projects without authentication if the initial request fails. - Added checks for empty responses and improved error reporting to include status codes and response texts for better diagnostics. - Enhanced overall robustness of the API interaction, providing clearer feedback during the fetching process. * feat: Add remote load testing capabilities to Makefile - Introduced new commands for setting up and running load tests against remote Langflow instances. - Added checks for the required LANGFLOW_HOST environment variable and provided user feedback for setup and execution. - Updated load test help documentation to include instructions for remote testing, enhancing usability for users. - Improved overall structure and clarity of load testing commands in the Makefile. * feat: Add single request test for Langflow load testing - Introduced a new function `test_single_request` to validate the setup by testing a single flow request before executing load tests. - Implemented connectivity checks and response validation to ensure the Langflow instance is operational. - Updated the load test script to abort if the single request test fails, enhancing robustness and user feedback. - Adjusted default user count in load test options from 10 to 50 for improved testing scenarios. * feat: Update load test scripts to use credentials from JSON files and adjust user counts * docs: Update README with additional notes for remote testing best practices * feat: Enhance error logging in load testing scripts - Updated the `log_detailed_error` function to accept an additional `traceback` parameter for improved error reporting. - Enhanced exception handling in the `BaseLangflowUser` class to capture detailed error information, including connection issues and timeouts. - Improved logging of connection errors by providing structured error details in the response text, aiding in diagnostics during load tests. * docs: Update README to enhance load testing instructions and features - Added sections for pre-flight testing and enhanced error logging to improve user experience. - Introduced Makefile commands for easier setup and execution of load tests. - Updated remote testing instructions and clarified the use of default credentials. - Improved troubleshooting tips and added a diagnostic tool for remote instances. * feat: Add diagnostic tool for remote Langflow instances - Introduced a new script `diagnose_remote.py` to assist in debugging connection issues and performance problems with remote Langflow instances. - Implemented functions for testing connectivity, flow execution, and running load simulations, providing detailed feedback on each step. - Added command-line arguments for user flexibility, including options for saving results to a JSON file. - Enhanced user experience with clear output messages and recommendations based on diagnostic results. * feat: Enhance load test commands in Makefile for automatic setup and flow selection - Updated `load_test_run`, `load_test_langflow_quick`, and `load_test_stress` commands to automatically set up credentials if not found. - Added support for specifying flow names via the `FLOW_NAME` environment variable, improving user experience and flexibility. - Enhanced error messages to guide users in selecting available flows, ensuring smoother execution of load tests. * feat: Update flow descriptions and enhance endpoint name sanitization in load testing setup - Improved descriptions of known starter projects to include load testing suitability and requirements. - Enhanced the uniqueness and validity of the `endpoint_name` by sanitizing it to allow only letters, numbers, hyphens, and underscores, ensuring better compliance with API standards. * [autofix.ci] apply automated fixes * revert: remove unintended formatting changes * feat: update locust dependency to version 2.40.5 in pyproject.toml and uv.lock * Update uv.lock * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
794 lines
30 KiB
Makefile
794 lines
30 KiB
Makefile
.PHONY: all init format_backend format lint build run_backend dev help tests coverage clean_python_cache clean_npm_cache clean_frontend_build clean_all run_clic load_test_setup load_test_setup_basic load_test_list_flows load_test_run load_test_langflow_quick load_test_stress load_test_example load_test_clean load_test_remote_setup load_test_remote_run load_test_help
|
|
|
|
# Configurations
|
|
VERSION=$(shell grep "^version" pyproject.toml | sed 's/.*\"\(.*\)\"$$/\1/')
|
|
DOCKER=podman
|
|
DOCKERFILE=docker/build_and_push.Dockerfile
|
|
DOCKERFILE_BACKEND=docker/build_and_push_backend.Dockerfile
|
|
DOCKERFILE_FRONTEND=docker/frontend/build_and_push_frontend.Dockerfile
|
|
DOCKER_COMPOSE=docker_example/docker-compose.yml
|
|
PYTHON_REQUIRED=$(shell grep '^requires-python[[:space:]]*=' pyproject.toml | sed -n 's/.*"\([^"]*\)".*/\1/p')
|
|
RED=\033[0;31m
|
|
NC=\033[0m # No Color
|
|
GREEN=\033[0;32m
|
|
YELLOW=\033[1;33m
|
|
|
|
log_level ?= debug
|
|
host ?= 0.0.0.0
|
|
port ?= 7860
|
|
env ?= .env
|
|
open_browser ?= true
|
|
path = src/backend/base/langflow/frontend
|
|
workers ?= 1
|
|
async ?= true
|
|
lf ?= false
|
|
ff ?= true
|
|
all: help
|
|
|
|
######################
|
|
# UTILITIES
|
|
######################
|
|
|
|
# Some directories may be mount points as in devcontainer, so we need to clear their
|
|
# contents rather than remove the entire directory. But we must also be mindful that
|
|
# we are not running in a devcontainer, so need to ensure the directories exist.
|
|
# See https://code.visualstudio.com/remote/advancedcontainers/improve-performance
|
|
CLEAR_DIRS = $(foreach dir,$1,$(shell mkdir -p $(dir) && find $(dir) -mindepth 1 -delete))
|
|
|
|
# check for required tools
|
|
check_tools:
|
|
@command -v uv >/dev/null 2>&1 || { echo >&2 "$(RED)uv is not installed. Aborting.$(NC)"; exit 1; }
|
|
@command -v npm >/dev/null 2>&1 || { echo >&2 "$(RED)NPM is not installed. Aborting.$(NC)"; exit 1; }
|
|
@echo "$(GREEN)All required tools are installed.$(NC)"
|
|
|
|
help: ## show this help message
|
|
@echo '----'
|
|
@grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | \
|
|
awk -F ':.*##' '{printf "\033[36mmake %s\033[0m: %s\n", $$1, $$2}' | \
|
|
column -c2 -t -s :
|
|
@echo '----'
|
|
@echo 'For frontend commands, run: make help_frontend'
|
|
|
|
######################
|
|
# INSTALL PROJECT
|
|
######################
|
|
|
|
reinstall_backend: ## forces reinstall all dependencies (no caching)
|
|
@echo 'Installing backend dependencies'
|
|
@uv sync -n --reinstall --frozen
|
|
|
|
install_backend: ## install the backend dependencies
|
|
@echo 'Installing backend dependencies'
|
|
@uv sync --frozen --extra "postgresql" $(EXTRA_ARGS)
|
|
|
|
|
|
|
|
init: check_tools ## initialize the project
|
|
@make install_backend
|
|
@make install_frontend
|
|
@uvx pre-commit install
|
|
@echo "$(GREEN)All requirements are installed.$(NC)"
|
|
|
|
######################
|
|
# CLEAN PROJECT
|
|
######################
|
|
|
|
clean_python_cache:
|
|
@echo "Cleaning Python cache..."
|
|
find . -type d -name '__pycache__' -exec rm -r {} +
|
|
find . -type f -name '*.py[cod]' -exec rm -f {} +
|
|
find . -type f -name '*~' -exec rm -f {} +
|
|
find . -type f -name '.*~' -exec rm -f {} +
|
|
$(call CLEAR_DIRS,.mypy_cache )
|
|
@echo "$(GREEN)Python cache cleaned.$(NC)"
|
|
|
|
clean_npm_cache:
|
|
@echo "Cleaning npm cache..."
|
|
cd src/frontend && npm cache clean --force
|
|
$(call CLEAR_DIRS,src/frontend/node_modules src/frontend/build src/backend/base/langflow/frontend)
|
|
rm -f src/frontend/package-lock.json
|
|
@echo "$(GREEN)NPM cache and frontend directories cleaned.$(NC)"
|
|
|
|
clean_frontend_build: ## clean frontend build artifacts to ensure fresh build
|
|
@echo "Cleaning frontend build artifacts..."
|
|
@echo " - Removing src/frontend/build directory"
|
|
$(call CLEAR_DIRS,src/frontend/build)
|
|
@echo " - Removing built frontend files from backend"
|
|
$(call CLEAR_DIRS,src/backend/base/langflow/frontend)
|
|
@echo "$(GREEN)Frontend build artifacts cleaned - fresh build guaranteed.$(NC)"
|
|
|
|
clean_all: clean_python_cache clean_npm_cache # clean all caches and temporary directories
|
|
@echo "$(GREEN)All caches and temporary directories cleaned.$(NC)"
|
|
|
|
setup_uv: ## install uv using pipx
|
|
pipx install uv
|
|
|
|
add:
|
|
@echo 'Adding dependencies'
|
|
ifdef devel
|
|
@cd src/backend/base && uv add --group dev $(devel)
|
|
endif
|
|
|
|
ifdef main
|
|
@uv add $(main)
|
|
endif
|
|
|
|
ifdef base
|
|
@cd src/backend/base && uv add $(base)
|
|
endif
|
|
|
|
|
|
|
|
######################
|
|
# CODE TESTS
|
|
######################
|
|
|
|
coverage: ## run the tests and generate a coverage report
|
|
@uv run coverage run
|
|
@uv run coverage erase
|
|
|
|
unit_tests: ## run unit tests
|
|
@uv sync --frozen
|
|
@EXTRA_ARGS=""
|
|
@if [ "$(async)" = "true" ]; then \
|
|
EXTRA_ARGS="$$EXTRA_ARGS --instafail -n auto"; \
|
|
fi; \
|
|
if [ "$(lf)" = "true" ]; then \
|
|
EXTRA_ARGS="$$EXTRA_ARGS --lf"; \
|
|
fi; \
|
|
if [ "$(ff)" = "true" ]; then \
|
|
EXTRA_ARGS="$$EXTRA_ARGS --ff"; \
|
|
fi; \
|
|
uv run pytest src/backend/tests/unit \
|
|
--ignore=src/backend/tests/integration \
|
|
--ignore=src/backend/tests/unit/template \
|
|
$$EXTRA_ARGS \
|
|
--instafail -ra -m 'not api_key_required' \
|
|
--durations-path src/backend/tests/.test_durations \
|
|
--splitting-algorithm least_duration $(args)
|
|
|
|
unit_tests_looponfail:
|
|
@make unit_tests args="-f"
|
|
|
|
lfx_tests: ## run lfx package unit tests
|
|
@echo 'Running LFX Package Tests...'
|
|
@cd src/lfx && \
|
|
uv sync && \
|
|
uv run pytest tests/unit -v $(args)
|
|
|
|
integration_tests:
|
|
uv run pytest src/backend/tests/integration \
|
|
--instafail -ra \
|
|
$(args)
|
|
|
|
integration_tests_no_api_keys:
|
|
uv run pytest src/backend/tests/integration \
|
|
--instafail -ra -m "not api_key_required" \
|
|
$(args)
|
|
|
|
integration_tests_api_keys:
|
|
uv run pytest src/backend/tests/integration \
|
|
--instafail -ra -m "api_key_required" \
|
|
$(args)
|
|
|
|
tests: ## run unit, integration, coverage tests
|
|
@echo 'Running Unit Tests...'
|
|
make unit_tests
|
|
@echo 'Running Integration Tests...'
|
|
make integration_tests
|
|
@echo 'Running Coverage Tests...'
|
|
make coverage
|
|
|
|
######################
|
|
# TEMPLATE TESTING
|
|
######################
|
|
|
|
template_tests: ## run all starter project template tests
|
|
@echo 'Running Starter Project Template Tests...'
|
|
@uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v -n auto
|
|
|
|
######################
|
|
# CODE QUALITY
|
|
######################
|
|
|
|
codespell: ## run codespell to check spelling
|
|
@uvx codespell --toml pyproject.toml
|
|
|
|
fix_codespell: ## run codespell to fix spelling errors
|
|
@uvx codespell --toml pyproject.toml --write
|
|
|
|
format_backend: ## backend code formatters
|
|
@uv run ruff check . --fix
|
|
@uv run ruff format .
|
|
|
|
format: format_backend format_frontend ## run code formatters
|
|
|
|
format_frontend_check: ## run biome check without formatting
|
|
@echo 'Running Biome check on frontend...'
|
|
@cd src/frontend && npx @biomejs/biome check
|
|
|
|
unsafe_fix:
|
|
@uv run ruff check . --fix --unsafe-fixes
|
|
|
|
lint: install_backend ## run linters
|
|
@uv run mypy --namespace-packages -p "langflow"
|
|
|
|
|
|
|
|
run_clic: clean_frontend_build install_frontend install_backend build_frontend ## run the CLI with fresh frontend build
|
|
@echo 'Running the CLI with fresh frontend build'
|
|
@uv run langflow run \
|
|
--frontend-path $(path) \
|
|
--log-level $(log_level) \
|
|
--host $(host) \
|
|
--port $(port) \
|
|
$(if $(env),--env-file $(env),) \
|
|
$(if $(filter false,$(open_browser)),--no-open-browser)
|
|
|
|
run_cli: install_frontend install_backend build_frontend ## run the CLI quickly (without cleaning build cache)
|
|
@echo 'Running the CLI quickly (reusing existing build cache if available)'
|
|
@uv run langflow run \
|
|
--frontend-path $(path) \
|
|
--log-level $(log_level) \
|
|
--host $(host) \
|
|
--port $(port) \
|
|
$(if $(env),--env-file $(env),) \
|
|
$(if $(filter false,$(open_browser)),--no-open-browser)
|
|
|
|
run_cli_debug:
|
|
@echo 'Running the CLI in debug mode'
|
|
@make install_frontend > /dev/null
|
|
@echo 'Building the frontend'
|
|
@make build_frontend > /dev/null
|
|
@echo 'Install backend dependencies'
|
|
@make install_backend > /dev/null
|
|
ifdef env
|
|
@make start env=$(env) host=$(host) port=$(port) log_level=debug
|
|
else
|
|
@make start host=$(host) port=$(port) log_level=debug
|
|
endif
|
|
|
|
|
|
setup_devcontainer: ## set up the development container
|
|
make install_backend
|
|
make install_frontend
|
|
make build_frontend
|
|
uv run langflow --frontend-path src/frontend/build
|
|
|
|
setup_env: ## set up the environment
|
|
@sh ./scripts/setup/setup_env.sh
|
|
|
|
|
|
|
|
|
|
backend: setup_env install_backend ## run the backend in development mode
|
|
@-kill -9 $$(lsof -t -i:7860) || true
|
|
ifdef login
|
|
@echo "Running backend autologin is $(login)";
|
|
LANGFLOW_AUTO_LOGIN=$(login) uv run uvicorn \
|
|
--factory langflow.main:create_app \
|
|
--host 0.0.0.0 \
|
|
--port $(port) \
|
|
$(if $(filter-out 1,$(workers)),, --reload) \
|
|
--env-file $(env) \
|
|
--loop asyncio \
|
|
$(if $(workers),--workers $(workers),)
|
|
else
|
|
@echo "Running backend respecting the $(env) file";
|
|
uv run uvicorn \
|
|
--factory langflow.main:create_app \
|
|
--host 0.0.0.0 \
|
|
--port $(port) \
|
|
$(if $(filter-out 1,$(workers)),, --reload) \
|
|
--env-file $(env) \
|
|
--loop asyncio \
|
|
$(if $(workers),--workers $(workers),)
|
|
endif
|
|
|
|
build_and_run: setup_env ## build the project and run it
|
|
$(call CLEAR_DIRS,dist src/backend/base/dist)
|
|
make build
|
|
uv run pip install dist/*.tar.gz
|
|
uv run langflow run
|
|
|
|
build_and_install: ## build the project and install it
|
|
@echo 'Removing dist folder'
|
|
$(call CLEAR_DIRS,dist src/backend/base/dist)
|
|
make build && uv run pip install dist/*.whl && pip install src/backend/base/dist/*.whl --force-reinstall
|
|
|
|
build: setup_env ## build the frontend static files and package the project
|
|
ifdef base
|
|
make install_frontendci
|
|
make build_frontend
|
|
make build_langflow_base args="$(args)"
|
|
endif
|
|
|
|
ifdef main
|
|
make install_frontendci
|
|
make build_frontend
|
|
make build_langflow_base args="$(args)"
|
|
make build_langflow args="$(args)"
|
|
endif
|
|
|
|
build_langflow_base:
|
|
cd src/backend/base && uv build $(args)
|
|
|
|
build_langflow_backup:
|
|
uv lock && uv build
|
|
|
|
build_langflow:
|
|
uv lock --no-upgrade
|
|
uv build $(args)
|
|
ifdef restore
|
|
mv pyproject.toml.bak pyproject.toml
|
|
mv uv.lock.bak uv.lock
|
|
endif
|
|
|
|
|
|
docker_build: dockerfile_build clear_dockerimage ## build DockerFile
|
|
|
|
docker_build_backend: dockerfile_build_be clear_dockerimage ## build Backend DockerFile
|
|
|
|
docker_build_frontend: dockerfile_build_fe clear_dockerimage ## build Frontend Dockerfile
|
|
|
|
dockerfile_build:
|
|
@echo 'BUILDING DOCKER IMAGE: ${DOCKERFILE}'
|
|
@command -v $(DOCKER) >/dev/null 2>&1 || { echo "Error: $(DOCKER) is not installed. Please install $(DOCKER), or run 'make docker_build DOCKER=podman' (or DOCKER=docker) if you have an alternative installed."; exit 1; }
|
|
@$(DOCKER) build --rm \
|
|
-f ${DOCKERFILE} \
|
|
-t langflow:${VERSION} .
|
|
|
|
dockerfile_build_be: dockerfile_build
|
|
@echo 'BUILDING DOCKER IMAGE BACKEND: ${DOCKERFILE_BACKEND}'
|
|
@command -v $(DOCKER) >/dev/null 2>&1 || { echo "Error: $(DOCKER) is not installed. Please install $(DOCKER), or run 'make docker_build_backend DOCKER=podman' (or DOCKER=docker) if you have an alternative installed."; exit 1; }
|
|
@$(DOCKER) build --rm \
|
|
--build-arg LANGFLOW_IMAGE=langflow:${VERSION} \
|
|
-f ${DOCKERFILE_BACKEND} \
|
|
-t langflow_backend:${VERSION} .
|
|
|
|
dockerfile_build_fe: dockerfile_build
|
|
@echo 'BUILDING DOCKER IMAGE FRONTEND: ${DOCKERFILE_FRONTEND}'
|
|
@command -v $(DOCKER) >/dev/null 2>&1 || { echo "Error: $(DOCKER) is not installed. Please install $(DOCKER), or run 'make docker_build_frontend DOCKER=podman' (or DOCKER=docker) if you have an alternative installed."; exit 1; }
|
|
@$(DOCKER) build --rm \
|
|
--build-arg LANGFLOW_IMAGE=langflow:${VERSION} \
|
|
-f ${DOCKERFILE_FRONTEND} \
|
|
-t langflow_frontend:${VERSION} .
|
|
|
|
clear_dockerimage:
|
|
@echo 'Clearing the docker build'
|
|
@if $(DOCKER) images -f "dangling=true" -q | grep -q '.*'; then \
|
|
$(DOCKER) rmi $$($(DOCKER) images -f "dangling=true" -q); \
|
|
fi
|
|
|
|
docker_compose_up: docker_build docker_compose_down
|
|
@echo 'Running docker compose up'
|
|
$(DOCKER) compose -f $(DOCKER_COMPOSE) up --remove-orphans
|
|
|
|
docker_compose_down:
|
|
@echo 'Running docker compose down'
|
|
$(DOCKER) compose -f $(DOCKER_COMPOSE) down || true
|
|
|
|
dcdev_up:
|
|
@echo 'Running docker compose up'
|
|
$(DOCKER) compose -f docker/dev.docker-compose.yml down || true
|
|
$(DOCKER) compose -f docker/dev.docker-compose.yml up --remove-orphans
|
|
|
|
lock_base:
|
|
cd src/backend/base && uv lock
|
|
|
|
lock_langflow:
|
|
uv lock
|
|
|
|
lock: ## lock dependencies
|
|
@echo 'Locking dependencies'
|
|
cd src/backend/base && uv lock
|
|
uv lock
|
|
|
|
update: ## update dependencies
|
|
@echo 'Updating dependencies'
|
|
cd src/backend/base && uv sync --upgrade
|
|
uv sync --upgrade
|
|
|
|
publish_base:
|
|
cd src/backend/base && uv publish
|
|
|
|
publish_langflow:
|
|
uv publish
|
|
|
|
publish_base_testpypi:
|
|
# TODO: update this to use the test-pypi repository
|
|
cd src/backend/base && uv publish -r test-pypi
|
|
|
|
publish_langflow_testpypi:
|
|
# TODO: update this to use the test-pypi repository
|
|
uv publish -r test-pypi
|
|
|
|
publish: ## build the frontend static files and package the project and publish it to PyPI
|
|
@echo 'Publishing the project'
|
|
ifdef base
|
|
make publish_base
|
|
endif
|
|
|
|
ifdef main
|
|
make publish_langflow
|
|
endif
|
|
|
|
publish_testpypi: ## build the frontend static files and package the project and publish it to PyPI
|
|
@echo 'Publishing the project'
|
|
|
|
######################
|
|
# LFX PACKAGE
|
|
######################
|
|
|
|
lfx_build: ## build the LFX package
|
|
@echo 'Building LFX package'
|
|
@cd src/lfx && make build
|
|
|
|
lfx_publish: ## publish LFX package to PyPI
|
|
@echo 'Publishing LFX package'
|
|
@cd src/lfx && make publish
|
|
|
|
lfx_publish_testpypi: ## publish LFX package to test PyPI
|
|
@echo 'Publishing LFX package to test PyPI'
|
|
@cd src/lfx && make publish_test
|
|
|
|
lfx_test: ## run LFX tests
|
|
@echo 'Running LFX tests'
|
|
@cd src/lfx && make test
|
|
|
|
lfx_format: ## format LFX code
|
|
@echo 'Formatting LFX code'
|
|
@cd src/lfx && make format
|
|
|
|
lfx_lint: ## lint LFX code
|
|
@echo 'Linting LFX code'
|
|
@cd src/lfx && make lint
|
|
|
|
lfx_clean: ## clean LFX build artifacts
|
|
@echo 'Cleaning LFX build artifacts'
|
|
@cd src/lfx && make clean
|
|
|
|
lfx_docker_build: ## build LFX production Docker image
|
|
@echo 'Building LFX Docker image'
|
|
@cd src/lfx && make docker_build
|
|
|
|
lfx_docker_dev: ## start LFX development environment
|
|
@echo 'Starting LFX development environment'
|
|
@cd src/lfx && make docker_dev
|
|
|
|
lfx_docker_test: ## run LFX tests in Docker
|
|
@echo 'Running LFX tests in Docker'
|
|
@cd src/lfx && make docker_test
|
|
|
|
# example make alembic-revision message="Add user table"
|
|
alembic-revision: ## generate a new migration
|
|
@echo 'Generating a new Alembic revision'
|
|
cd src/backend/base/langflow/ && uv run alembic revision --autogenerate -m "$(message)"
|
|
|
|
|
|
alembic-upgrade: ## upgrade database to the latest version
|
|
@echo 'Upgrading database to the latest version'
|
|
cd src/backend/base/langflow/ && uv run alembic upgrade head
|
|
|
|
alembic-downgrade: ## downgrade database by one version
|
|
@echo 'Downgrading database by one version'
|
|
cd src/backend/base/langflow/ && uv run alembic downgrade -1
|
|
|
|
alembic-current: ## show current revision
|
|
@echo 'Showing current Alembic revision'
|
|
cd src/backend/base/langflow/ && uv run alembic current
|
|
|
|
alembic-history: ## show migration history
|
|
@echo 'Showing Alembic migration history'
|
|
cd src/backend/base/langflow/ && uv run alembic history --verbose
|
|
|
|
alembic-check: ## check migration status
|
|
@echo 'Running alembic check'
|
|
cd src/backend/base/langflow/ && uv run alembic check
|
|
|
|
alembic-stamp: ## stamp the database with a specific revision
|
|
@echo 'Stamping the database with revision $(revision)'
|
|
cd src/backend/base/langflow/ && uv run alembic stamp $(revision)
|
|
|
|
######################
|
|
# VERSION MANAGEMENT
|
|
######################
|
|
|
|
patch: ## Update version across all projects. Usage: make patch v=1.5.0
|
|
@if [ -z "$(v)" ]; then \
|
|
echo "$(RED)Error: Version argument required.$(NC)"; \
|
|
echo "Usage: make patch v=1.5.0"; \
|
|
exit 1; \
|
|
fi; \
|
|
echo "$(GREEN)Updating version to $(v)$(NC)"; \
|
|
\
|
|
LANGFLOW_VERSION="$(v)"; \
|
|
LANGFLOW_BASE_VERSION=$$(echo "$$LANGFLOW_VERSION" | sed -E 's/^[0-9]+\.(.*)$$/0.\1/'); \
|
|
\
|
|
echo "$(GREEN)Langflow version: $$LANGFLOW_VERSION$(NC)"; \
|
|
echo "$(GREEN)Langflow-base version: $$LANGFLOW_BASE_VERSION$(NC)"; \
|
|
\
|
|
echo "$(GREEN)Updating main pyproject.toml...$(NC)"; \
|
|
python -c "import re; fname='pyproject.toml'; txt=open(fname).read(); txt=re.sub(r'^version = \".*\"', 'version = \"$$LANGFLOW_VERSION\"', txt, flags=re.MULTILINE); txt=re.sub(r'\"langflow-base==.*\"', '\"langflow-base==$$LANGFLOW_BASE_VERSION\"', txt); open(fname, 'w').write(txt)"; \
|
|
\
|
|
echo "$(GREEN)Updating langflow-base pyproject.toml...$(NC)"; \
|
|
python -c "import re; fname='src/backend/base/pyproject.toml'; txt=open(fname).read(); txt=re.sub(r'^version = \".*\"', 'version = \"$$LANGFLOW_BASE_VERSION\"', txt, flags=re.MULTILINE); open(fname, 'w').write(txt)"; \
|
|
\
|
|
echo "$(GREEN)Updating frontend package.json...$(NC)"; \
|
|
python -c "import re; fname='src/frontend/package.json'; txt=open(fname).read(); txt=re.sub(r'\"version\": \".*\"', '\"version\": \"$$LANGFLOW_VERSION\"', txt); open(fname, 'w').write(txt)"; \
|
|
\
|
|
echo "$(GREEN)Validating version changes...$(NC)"; \
|
|
if ! grep -q "^version = \"$$LANGFLOW_VERSION\"" pyproject.toml; then echo "$(RED)✗ Main pyproject.toml version validation failed$(NC)"; exit 1; fi; \
|
|
if ! grep -q "\"langflow-base==$$LANGFLOW_BASE_VERSION\"" pyproject.toml; then echo "$(RED)✗ Main pyproject.toml langflow-base dependency validation failed$(NC)"; exit 1; fi; \
|
|
if ! grep -q "^version = \"$$LANGFLOW_BASE_VERSION\"" src/backend/base/pyproject.toml; then echo "$(RED)✗ Langflow-base pyproject.toml version validation failed$(NC)"; exit 1; fi; \
|
|
if ! grep -q "\"version\": \"$$LANGFLOW_VERSION\"" src/frontend/package.json; then echo "$(RED)✗ Frontend package.json version validation failed$(NC)"; exit 1; fi; \
|
|
echo "$(GREEN)✓ All versions updated successfully$(NC)"; \
|
|
\
|
|
echo "$(GREEN)Syncing dependencies in parallel...$(NC)"; \
|
|
uv sync --quiet & \
|
|
(cd src/frontend && npm install --silent) & \
|
|
wait; \
|
|
\
|
|
echo "$(GREEN)Validating final state...$(NC)"; \
|
|
CHANGED_FILES=$$(git status --porcelain | wc -l | tr -d ' '); \
|
|
if [ "$$CHANGED_FILES" -lt 5 ]; then \
|
|
echo "$(RED)✗ Expected at least 5 changed files, but found $$CHANGED_FILES$(NC)"; \
|
|
echo "$(RED)Changed files:$(NC)"; \
|
|
git status --porcelain; \
|
|
exit 1; \
|
|
fi; \
|
|
EXPECTED_FILES="pyproject.toml uv.lock src/backend/base/pyproject.toml src/frontend/package.json src/frontend/package-lock.json"; \
|
|
for file in $$EXPECTED_FILES; do \
|
|
if ! git status --porcelain | grep -q "$$file"; then \
|
|
echo "$(RED)✗ Expected file $$file was not modified$(NC)"; \
|
|
exit 1; \
|
|
fi; \
|
|
done; \
|
|
echo "$(GREEN)✓ All required files were modified.$(NC)"; \
|
|
\
|
|
echo "$(GREEN)Version update complete!$(NC)"; \
|
|
echo "$(GREEN)Updated files:$(NC)"; \
|
|
echo " - pyproject.toml: $$LANGFLOW_VERSION"; \
|
|
echo " - src/backend/base/pyproject.toml: $$LANGFLOW_BASE_VERSION"; \
|
|
echo " - src/frontend/package.json: $$LANGFLOW_VERSION"; \
|
|
echo " - uv.lock: dependency lock updated"; \
|
|
echo " - src/frontend/package-lock.json: dependency lock updated"; \
|
|
echo "$(GREEN)Dependencies synced successfully!$(NC)"
|
|
|
|
######################
|
|
# LOAD TESTING
|
|
######################
|
|
|
|
# Default values for locust configuration
|
|
locust_users ?= 10
|
|
locust_spawn_rate ?= 1
|
|
locust_host ?= http://localhost:7860
|
|
locust_headless ?= true
|
|
locust_time ?= 300s
|
|
locust_api_key ?= your-api-key
|
|
locust_flow_id ?= your-flow-id
|
|
locust_file ?= src/backend/tests/locust/locustfile.py
|
|
locust_min_wait ?= 2000
|
|
locust_max_wait ?= 5000
|
|
locust_request_timeout ?= 30.0
|
|
|
|
locust: ## run locust load tests (options: locust_users=10 locust_spawn_rate=1 locust_host=http://localhost:7860 locust_headless=true locust_time=300s locust_api_key=your-api-key locust_flow_id=your-flow-id locust_file=src/backend/tests/locust/locustfile.py locust_min_wait=2000 locust_max_wait=5000 locust_request_timeout=30.0)
|
|
@if [ ! -f "$(locust_file)" ]; then \
|
|
echo "$(RED)Error: Locustfile not found at $(locust_file)$(NC)"; \
|
|
exit 1; \
|
|
fi
|
|
@echo "Starting Locust with $(locust_users) users, spawn rate of $(locust_spawn_rate)"
|
|
@echo "Testing host: $(locust_host)"
|
|
@echo "Using locustfile: $(locust_file)"
|
|
@export API_KEY=$(locust_api_key) && \
|
|
export FLOW_ID=$(locust_flow_id) && \
|
|
export LANGFLOW_HOST=$(locust_host) && \
|
|
export MIN_WAIT=$(locust_min_wait) && \
|
|
export MAX_WAIT=$(locust_max_wait) && \
|
|
export REQUEST_TIMEOUT=$(locust_request_timeout) && \
|
|
cd $$(dirname "$(locust_file)") && \
|
|
if [ "$(locust_headless)" = "true" ]; then \
|
|
uv run locust \
|
|
--headless \
|
|
-u $(locust_users) \
|
|
-r $(locust_spawn_rate) \
|
|
--run-time $(locust_time) \
|
|
--host $(locust_host) \
|
|
-f $$(basename "$(locust_file)"); \
|
|
else \
|
|
uv run locust \
|
|
-u $(locust_users) \
|
|
-r $(locust_spawn_rate) \
|
|
--host $(locust_host) \
|
|
-f $$(basename "$(locust_file)"); \
|
|
fi
|
|
|
|
# Enhanced load testing targets with improved error handling and shapes
|
|
load_test_host ?= http://127.0.0.1:8000
|
|
load_test_flow_id ?= 5523731d-5ef3-56de-b4ef-59b0a224fdbc
|
|
load_test_api_key ?= test
|
|
html ?= false
|
|
|
|
load_test_ramp100: ## Run 100-user ramp load test (3min, 0->100 users @ 5/s). Options: html=true, load_test_host, load_test_flow_id, load_test_api_key
|
|
@echo "$(YELLOW)Running 100-user ramp load test (3 minutes)$(NC)"
|
|
@export FLOW_ID=$(load_test_flow_id) && \
|
|
export API_KEY=$(load_test_api_key) && \
|
|
export REQUEST_TIMEOUT=10 && \
|
|
cd src/backend/tests/locust && \
|
|
if [ "$(html)" = "true" ]; then \
|
|
echo "$(GREEN)Generating HTML report: ramp100_test.html$(NC)"; \
|
|
uv run locust -f locustfile_complex_serve.py --host $(load_test_host) --headless --html ramp100_test.html; \
|
|
else \
|
|
uv run locust -f locustfile_complex_serve.py --host $(load_test_host) --headless; \
|
|
fi
|
|
|
|
load_test_cliff: ## Find performance cliff with step ramp (5->50 users, 30s steps). Options: html=true, load_test_host, load_test_flow_id, load_test_api_key
|
|
@echo "$(YELLOW)Running step ramp to find performance cliff$(NC)"
|
|
@export FLOW_ID=$(load_test_flow_id) && \
|
|
export API_KEY=$(load_test_api_key) && \
|
|
export REQUEST_TIMEOUT=10 && \
|
|
cd src/backend/tests/locust && \
|
|
if [ "$(html)" = "true" ]; then \
|
|
echo "$(GREEN)Generating HTML report: cliff_test.html$(NC)"; \
|
|
uv run locust -f lfx_step_ramp.py --host $(load_test_host) --headless --html cliff_test.html; \
|
|
else \
|
|
uv run locust -f lfx_step_ramp.py --host $(load_test_host) --headless; \
|
|
fi
|
|
|
|
load_test_lfx_quick: ## Quick LFX load test (30 users, 60s). Options: html=true, load_test_host, load_test_flow_id, load_test_api_key
|
|
@echo "$(YELLOW)Running quick 30-user load test (60 seconds)$(NC)"
|
|
@export FLOW_ID=$(load_test_flow_id) && \
|
|
export API_KEY=$(load_test_api_key) && \
|
|
export REQUEST_TIMEOUT=10 && \
|
|
cd src/backend/tests/locust && \
|
|
if [ "$(html)" = "true" ]; then \
|
|
echo "$(GREEN)Generating HTML report: quick_test.html$(NC)"; \
|
|
uv run locust -f lfx_serve_locustfile.py --host $(load_test_host) --headless -u 30 -r 5 -t 60s --html quick_test.html; \
|
|
else \
|
|
uv run locust -f lfx_serve_locustfile.py --host $(load_test_host) --headless -u 30 -r 5 -t 60s; \
|
|
fi
|
|
|
|
######################
|
|
# ENHANCED LOAD TESTING
|
|
######################
|
|
|
|
# Enhanced load testing system with API-based flow loading
|
|
load_test_setup: ## Set up load test environment with starter project flows
|
|
@echo "$(YELLOW)Setting up Langflow load test environment$(NC)"
|
|
@cd src/backend/tests/locust && uv run python langflow_setup_test.py --interactive
|
|
|
|
load_test_setup_basic: ## Set up load test environment with Basic Prompting flow
|
|
@echo "$(YELLOW)Setting up load test environment with Basic Prompting flow$(NC)"
|
|
@cd src/backend/tests/locust && uv run python langflow_setup_test.py --flow "Basic Prompting" --save-credentials load_test_creds.json
|
|
|
|
load_test_list_flows: ## List available starter project flows
|
|
@echo "$(YELLOW)Listing available starter project flows$(NC)"
|
|
@cd src/backend/tests/locust && uv run python langflow_setup_test.py --list-flows
|
|
|
|
load_test_run: ## Run load test (automatically sets up if needed). Use FLOW_NAME="Flow Name" to specify flow
|
|
@echo "$(YELLOW)Running load test with enhanced error logging$(NC)"
|
|
@if [ ! -f "src/backend/tests/locust/load_test_creds.json" ]; then \
|
|
echo "$(BLUE)No credentials found. Running automatic setup...$(NC)"; \
|
|
if [ -z "$(FLOW_NAME)" ]; then \
|
|
echo "$(CYAN)Available flows:$(NC)"; \
|
|
cd src/backend/tests/locust && uv run python langflow_setup_test.py --list-flows; \
|
|
echo "$(RED)Please specify a flow: make load_test_run FLOW_NAME=\"Basic Prompting\"$(NC)"; \
|
|
exit 1; \
|
|
else \
|
|
echo "$(BLUE)Setting up with flow: $(FLOW_NAME)$(NC)"; \
|
|
cd src/backend/tests/locust && uv run python langflow_setup_test.py --flow "$(FLOW_NAME)" --save-credentials load_test_creds.json; \
|
|
fi \
|
|
fi
|
|
@cd src/backend/tests/locust && \
|
|
export API_KEY=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['api_key'])") && \
|
|
export FLOW_ID=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['flow_id'])") && \
|
|
uv run python langflow_run_load_test.py --headless --users 20 --duration 120 --no-start-langflow --html load_test_report.html --csv load_test_results
|
|
|
|
load_test_langflow_quick: ## Quick Langflow load test (10 users, 30s) with HTML report (automatically sets up if needed). Use FLOW_NAME="Flow Name" to specify flow
|
|
@echo "$(YELLOW)Running quick Langflow load test with HTML report$(NC)"
|
|
@if [ ! -f "src/backend/tests/locust/load_test_creds.json" ]; then \
|
|
echo "$(BLUE)No credentials found. Running automatic setup...$(NC)"; \
|
|
if [ -z "$(FLOW_NAME)" ]; then \
|
|
echo "$(CYAN)Available flows:$(NC)"; \
|
|
cd src/backend/tests/locust && uv run python langflow_setup_test.py --list-flows; \
|
|
echo "$(RED)Please specify a flow: make load_test_langflow_quick FLOW_NAME=\"Basic Prompting\"$(NC)"; \
|
|
exit 1; \
|
|
else \
|
|
echo "$(BLUE)Setting up with flow: $(FLOW_NAME)$(NC)"; \
|
|
cd src/backend/tests/locust && uv run python langflow_setup_test.py --flow "$(FLOW_NAME)" --save-credentials load_test_creds.json; \
|
|
fi \
|
|
fi
|
|
@cd src/backend/tests/locust && \
|
|
export API_KEY=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['api_key'])") && \
|
|
export FLOW_ID=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['flow_id'])") && \
|
|
uv run python langflow_run_load_test.py --headless --users 10 --duration 30 --no-start-langflow --html quick_test_report.html
|
|
|
|
load_test_stress: ## Stress test (100 users, 5 minutes) with comprehensive reporting (automatically sets up if needed). Use FLOW_NAME="Flow Name" to specify flow
|
|
@echo "$(YELLOW)Running stress test with comprehensive reporting$(NC)"
|
|
@if [ ! -f "src/backend/tests/locust/load_test_creds.json" ]; then \
|
|
echo "$(BLUE)No credentials found. Running automatic setup...$(NC)"; \
|
|
if [ -z "$(FLOW_NAME)" ]; then \
|
|
echo "$(CYAN)Available flows:$(NC)"; \
|
|
cd src/backend/tests/locust && uv run python langflow_setup_test.py --list-flows; \
|
|
echo "$(RED)Please specify a flow: make load_test_stress FLOW_NAME=\"Basic Prompting\"$(NC)"; \
|
|
exit 1; \
|
|
else \
|
|
echo "$(BLUE)Setting up with flow: $(FLOW_NAME)$(NC)"; \
|
|
cd src/backend/tests/locust && uv run python langflow_setup_test.py --flow "$(FLOW_NAME)" --save-credentials load_test_creds.json; \
|
|
fi \
|
|
fi
|
|
@cd src/backend/tests/locust && \
|
|
export API_KEY=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['api_key'])") && \
|
|
export FLOW_ID=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['flow_id'])") && \
|
|
uv run python langflow_run_load_test.py --headless --users 100 --spawn-rate 5 --duration 300 --no-start-langflow --html stress_test_report.html --csv stress_test_results --shape ramp100
|
|
|
|
load_test_example: ## Run complete example workflow (setup + test + reports)
|
|
@echo "$(YELLOW)Running complete load test example workflow$(NC)"
|
|
@cd src/backend/tests/locust && uv run python langflow_example_workflow.py --auto
|
|
|
|
load_test_clean: ## Clean up load test files and credentials
|
|
@echo "$(YELLOW)Cleaning up load test files$(NC)"
|
|
@cd src/backend/tests/locust && rm -f *.json *.html *.csv *.log
|
|
@echo "$(GREEN)Load test files cleaned$(NC)"
|
|
|
|
load_test_remote_setup: ## Set up load test for remote instance (requires LANGFLOW_HOST)
|
|
@if [ -z "$(LANGFLOW_HOST)" ]; then \
|
|
echo "$(RED)Error: LANGFLOW_HOST environment variable required$(NC)"; \
|
|
echo "$(YELLOW)Example: export LANGFLOW_HOST=https://your-remote-instance.com$(NC)"; \
|
|
exit 1; \
|
|
fi
|
|
@echo "$(YELLOW)Setting up load test for remote instance: $(LANGFLOW_HOST)$(NC)"
|
|
@cd src/backend/tests/locust && uv run python langflow_setup_test.py --host $(LANGFLOW_HOST) --flow "Basic Prompting" --save-credentials remote_test_creds.json
|
|
|
|
load_test_remote_run: ## Run load test against remote instance (requires prior setup)
|
|
@if [ -z "$(LANGFLOW_HOST)" ]; then \
|
|
echo "$(RED)Error: LANGFLOW_HOST environment variable required$(NC)"; \
|
|
exit 1; \
|
|
fi
|
|
@if [ ! -f "src/backend/tests/locust/remote_test_creds.json" ]; then \
|
|
echo "$(RED)Error: No remote credentials found. Run 'make load_test_remote_setup' first$(NC)"; \
|
|
exit 1; \
|
|
fi
|
|
@echo "$(YELLOW)Running load test against remote instance: $(LANGFLOW_HOST)$(NC)"
|
|
@cd src/backend/tests/locust && \
|
|
export API_KEY=$$(python -c "import json; print(json.load(open('remote_test_creds.json'))['api_key'])") && \
|
|
export FLOW_ID=$$(python -c "import json; print(json.load(open('remote_test_creds.json'))['flow_id'])") && \
|
|
uv run python langflow_run_load_test.py --host $(LANGFLOW_HOST) --no-start-langflow --headless --users 10 --spawn-rate 1 --duration 120 --html remote_test_report.html
|
|
|
|
load_test_help: ## Show detailed load testing help
|
|
@echo "$(GREEN)Langflow Enhanced Load Testing System$(NC)"
|
|
@echo ""
|
|
@echo "$(YELLOW)Quick Start (Local):$(NC)"
|
|
@echo " 1. make load_test_setup_basic # Set up with Basic Prompting flow"
|
|
@echo " 2. make load_test_langflow_quick # Run quick Langflow test"
|
|
@echo " 3. Open quick_test_report.html # View results"
|
|
@echo ""
|
|
@echo "$(YELLOW)Remote Testing:$(NC)"
|
|
@echo " 1. export LANGFLOW_HOST=https://your-instance.com"
|
|
@echo " 2. make load_test_remote_setup # Set up for remote testing"
|
|
@echo " 3. make load_test_remote_run # Run test against remote instance"
|
|
@echo ""
|
|
@echo "$(YELLOW)Available Commands:$(NC)"
|
|
@echo " load_test_setup - Interactive flow selection setup"
|
|
@echo " load_test_setup_basic - Quick setup with Basic Prompting"
|
|
@echo " load_test_list_flows - List available starter flows"
|
|
@echo " load_test_run - Standard load test (25 users, 2 min)"
|
|
@echo " load_test_langflow_quick - Quick Langflow test (10 users, 30s)"
|
|
@echo " load_test_quick - Quick complex serve test (30 users, 60s)"
|
|
@echo " load_test_stress - Stress test (100 users, 5 min)"
|
|
@echo " load_test_example - Complete example workflow"
|
|
@echo " load_test_clean - Clean up generated files"
|
|
@echo ""
|
|
@echo "$(YELLOW)Generated Reports:$(NC)"
|
|
@echo " - *.html files - Interactive HTML reports"
|
|
@echo " - *_results_*.csv - Raw performance data"
|
|
@echo " - *_detailed_errors_*.log - Comprehensive error logs"
|
|
@echo " - *_error_summary_*.json - Error analysis"
|
|
|
|
######################
|
|
# INCLUDE FRONTEND MAKEFILE
|
|
######################
|
|
|
|
# Include frontend-specific Makefile
|
|
include Makefile.frontend
|