tinybird 0.0.1.dev311__tar.gz → 0.0.1.dev312__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/PKG-INFO +1 -1
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/__cli__.py +2 -2
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/local.py +72 -18
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/local_common.py +275 -153
- tinybird-0.0.1.dev312/tinybird/tb/modules/local_logs.py +196 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird.egg-info/PKG-INFO +1 -1
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird.egg-info/SOURCES.txt +1 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/setup.cfg +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/__cli__.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/ch_utils/constants.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/ch_utils/engine.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/check_pypi.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/client.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/config.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/connectors.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/context.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/datafile/common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/datafile/exceptions.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/datafile/parse_connection.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/datafile/parse_datasource.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/datafile/parse_pipe.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/datatypes.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/feedback_manager.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/git_settings.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/prompts.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/service_datasources.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/sql.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/sql_template.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/sql_template_fmt.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/sql_toolset.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/syncasync.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/check_pypi.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/cli.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/client.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/config.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/__init__.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/agent.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/animations.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/banner.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/command_agent.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/compactor.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/explore_agent.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/file_agent.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/memory.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/mock_agent.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/models.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/prompts.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/testing_agent.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/__init__.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/analyze.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/append.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/build.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/datafile.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/deploy.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/deploy_check.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/diff_resource.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/execute_query.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/file.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/get_endpoint_stats.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/get_openapi_definition.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/mock.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/plan.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/request_endpoint.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/run_command.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/secret.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/tools/test.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/agent/utils.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/build.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/build_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/cicd.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/cli.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/config.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/connection.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/copy.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/create.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/build.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/build_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/build_datasource.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/build_pipe.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/diff.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/fixture.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/format_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/format_datasource.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/format_pipe.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/pipe_checker.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/playground.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datafile/pull.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/datasource.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/deployment.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/deployment_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/deprecations.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/dev_server.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/endpoint.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/environment.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/feedback_manager.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/info.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/infra.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/job.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/llm.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/llm_utils.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/login.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/login_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/logout.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/materialization.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/mock.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/mock_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/open.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/pipe.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/project.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/regions.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/secret.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/secret_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/shell.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/sink.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/table.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/test.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/test_common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/token.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/watch.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/workspace.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb/modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/auth.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/branch.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/cicd.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/cli.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/common.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/config.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/connection.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/datasource.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/exceptions.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/fmt.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/job.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/pipe.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/regions.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/tag.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/telemetry.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/test.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/tinyunit/tinyunit.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/tinyunit/tinyunit_lib.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/workspace.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tb_cli_modules/workspace_members.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird/tornado_template.py +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird.egg-info/dependency_links.txt +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird.egg-info/entry_points.txt +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird.egg-info/requires.txt +0 -0
- {tinybird-0.0.1.dev311 → tinybird-0.0.1.dev312}/tinybird.egg-info/top_level.txt +0 -0
|
@@ -4,5 +4,5 @@ __description__ = 'Tinybird Command Line Tool'
|
|
|
4
4
|
__url__ = 'https://www.tinybird.co/docs/forward/commands'
|
|
5
5
|
__author__ = 'Tinybird'
|
|
6
6
|
__author_email__ = 'support@tinybird.co'
|
|
7
|
-
__version__ = '0.0.1.
|
|
8
|
-
__revision__ = '
|
|
7
|
+
__version__ = '0.0.1.dev312'
|
|
8
|
+
__revision__ = '2324ba4'
|
|
@@ -10,7 +10,9 @@ from docker.client import DockerClient
|
|
|
10
10
|
|
|
11
11
|
from tinybird.tb.modules.cli import cli
|
|
12
12
|
from tinybird.tb.modules.common import echo_json, update_cli
|
|
13
|
+
from tinybird.tb.modules.exceptions import CLILocalException
|
|
13
14
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
15
|
+
from tinybird.tb.modules.info import get_local_info
|
|
14
16
|
from tinybird.tb.modules.local_common import (
|
|
15
17
|
TB_CONTAINER_NAME,
|
|
16
18
|
TB_LOCAL_ADDRESS,
|
|
@@ -18,6 +20,19 @@ from tinybird.tb.modules.local_common import (
|
|
|
18
20
|
get_existing_container_with_matching_env,
|
|
19
21
|
start_tinybird_local,
|
|
20
22
|
)
|
|
23
|
+
from tinybird.tb.modules.local_logs import (
|
|
24
|
+
check_memory_sufficient,
|
|
25
|
+
clickhouse_is_ready,
|
|
26
|
+
container_is_ready,
|
|
27
|
+
container_is_starting,
|
|
28
|
+
container_is_stopping,
|
|
29
|
+
container_is_unhealthy,
|
|
30
|
+
container_stats,
|
|
31
|
+
events_is_ready,
|
|
32
|
+
local_authentication_is_ready,
|
|
33
|
+
redis_is_ready,
|
|
34
|
+
server_is_ready,
|
|
35
|
+
)
|
|
21
36
|
|
|
22
37
|
|
|
23
38
|
def stop_tinybird_local(docker_client: DockerClient) -> None:
|
|
@@ -76,30 +91,69 @@ def stop() -> None:
|
|
|
76
91
|
@click.pass_context
|
|
77
92
|
def status(ctx: click.Context) -> None:
|
|
78
93
|
"""Check status of Tinybird Local"""
|
|
94
|
+
|
|
95
|
+
click.echo(FeedbackManager.highlight(message="» Checking status..."))
|
|
79
96
|
docker_client = get_docker_client()
|
|
80
97
|
container = get_existing_container_with_matching_env(docker_client, TB_CONTAINER_NAME, {})
|
|
81
98
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
try:
|
|
100
|
+
if container:
|
|
101
|
+
if container_is_ready(container):
|
|
102
|
+
stats = container_stats(container, docker_client)
|
|
103
|
+
click.echo(FeedbackManager.info(message=f"✓ Tinybird Local container ({stats})"))
|
|
104
|
+
|
|
105
|
+
# Check memory sufficiency
|
|
106
|
+
is_sufficient, warning_msg = check_memory_sufficient(container, docker_client)
|
|
107
|
+
if not is_sufficient and warning_msg:
|
|
108
|
+
click.echo(FeedbackManager.warning(message=f"△ {warning_msg}"))
|
|
109
|
+
|
|
110
|
+
if not clickhouse_is_ready(container):
|
|
111
|
+
raise Exception("Clickhouse is not ready.")
|
|
112
|
+
click.echo(FeedbackManager.info(message="✓ Clickhouse"))
|
|
113
|
+
|
|
114
|
+
if not redis_is_ready(container):
|
|
115
|
+
raise Exception("Redis is not ready.")
|
|
116
|
+
click.echo(FeedbackManager.info(message="✓ Redis"))
|
|
117
|
+
|
|
118
|
+
if not server_is_ready(container):
|
|
119
|
+
raise Exception("Server is not ready.")
|
|
120
|
+
click.echo(FeedbackManager.info(message="✓ Server"))
|
|
121
|
+
|
|
122
|
+
if not events_is_ready(container):
|
|
123
|
+
raise Exception("Events is not ready.")
|
|
124
|
+
click.echo(FeedbackManager.info(message="✓ Events"))
|
|
125
|
+
|
|
126
|
+
if not local_authentication_is_ready(container):
|
|
127
|
+
raise Exception("Tinybird Local authentication is not ready.")
|
|
128
|
+
click.echo(FeedbackManager.info(message="✓ Tinybird Local authentication"))
|
|
129
|
+
|
|
130
|
+
click.echo(FeedbackManager.success(message="✓ Tinybird Local is ready!"))
|
|
131
|
+
click.echo(FeedbackManager.highlight(message="\n» Tinybird Local:"))
|
|
132
|
+
config = ctx.ensure_object(dict).get("config", {})
|
|
133
|
+
get_local_info(config)
|
|
134
|
+
elif container_is_starting(container):
|
|
135
|
+
click.echo(FeedbackManager.highlight(message="* Tinybird Local is starting..."))
|
|
136
|
+
elif container_is_stopping(container):
|
|
137
|
+
click.echo(FeedbackManager.highlight(message="* Tinybird Local is stopping..."))
|
|
138
|
+
elif container_is_unhealthy(container):
|
|
139
|
+
is_sufficient, warning_msg = check_memory_sufficient(container, docker_client)
|
|
140
|
+
if not is_sufficient and warning_msg:
|
|
141
|
+
click.echo(FeedbackManager.warning(message=f"△ {warning_msg}"))
|
|
142
|
+
click.echo(
|
|
143
|
+
FeedbackManager.error(
|
|
144
|
+
message="* Tinybird Local is unhealthy. Try running `tb local restart` in a few seconds."
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
else:
|
|
148
|
+
click.echo(
|
|
149
|
+
FeedbackManager.error(message="✗ Tinybird Local is not running. Run 'tb local start' to start it")
|
|
150
|
+
)
|
|
97
151
|
else:
|
|
98
152
|
click.echo(
|
|
99
|
-
FeedbackManager.
|
|
153
|
+
FeedbackManager.error(message="✗ Tinybird Local is not running. Run 'tb local start' to start it")
|
|
100
154
|
)
|
|
101
|
-
|
|
102
|
-
|
|
155
|
+
except Exception as e:
|
|
156
|
+
raise CLILocalException(FeedbackManager.error(message=f"Tinybird Local is not ready. Reason: {e}"))
|
|
103
157
|
|
|
104
158
|
|
|
105
159
|
@local.command()
|
|
@@ -20,6 +20,15 @@ from tinybird.tb.client import AuthNoTokenException, TinyB
|
|
|
20
20
|
from tinybird.tb.modules.config import CLIConfig
|
|
21
21
|
from tinybird.tb.modules.exceptions import CLILocalException
|
|
22
22
|
from tinybird.tb.modules.feedback_manager import FeedbackManager
|
|
23
|
+
from tinybird.tb.modules.local_logs import (
|
|
24
|
+
check_memory_sufficient,
|
|
25
|
+
clickhouse_is_ready,
|
|
26
|
+
container_stats,
|
|
27
|
+
events_is_ready,
|
|
28
|
+
local_authentication_is_ready,
|
|
29
|
+
redis_is_ready,
|
|
30
|
+
server_is_ready,
|
|
31
|
+
)
|
|
23
32
|
from tinybird.tb.modules.secret_common import load_secrets
|
|
24
33
|
from tinybird.tb.modules.telemetry import add_telemetry_event
|
|
25
34
|
|
|
@@ -228,7 +237,7 @@ def get_local_tokens() -> Dict[str, str]:
|
|
|
228
237
|
default=True,
|
|
229
238
|
)
|
|
230
239
|
if yes:
|
|
231
|
-
click.echo(FeedbackManager.highlight(message="»
|
|
240
|
+
click.echo(FeedbackManager.highlight(message="» Watching Tinybird Local... (Press Ctrl+C to stop)"))
|
|
232
241
|
docker_client = get_docker_client()
|
|
233
242
|
start_tinybird_local(docker_client, False)
|
|
234
243
|
click.echo(FeedbackManager.success(message="✓ Tinybird Local is ready!"))
|
|
@@ -314,164 +323,84 @@ def start_tinybird_local(
|
|
|
314
323
|
# Stream logs in a separate thread while monitoring container health
|
|
315
324
|
container_ready = threading.Event()
|
|
316
325
|
stop_requested = threading.Event()
|
|
317
|
-
|
|
326
|
+
health_check: dict[str, str] = {}
|
|
318
327
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
# Give container a moment to fully start up
|
|
325
|
-
time.sleep(2)
|
|
326
|
-
|
|
327
|
-
check_interval = 10 # Check every 10 seconds
|
|
328
|
-
|
|
329
|
-
while not stop_requested.is_set():
|
|
330
|
-
try:
|
|
331
|
-
# Check /tokens endpoint
|
|
332
|
-
tokens_response = requests.get(f"{TB_LOCAL_ADDRESS}/tokens", timeout=5)
|
|
333
|
-
if tokens_response.status_code != 200:
|
|
334
|
-
health_check_error["message"] = (
|
|
335
|
-
f"/tokens endpoint returned status {tokens_response.status_code}. "
|
|
336
|
-
"Tinybird Local may be unhealthy."
|
|
337
|
-
)
|
|
338
|
-
stop_requested.set()
|
|
339
|
-
break
|
|
340
|
-
|
|
341
|
-
# Check /v0/health endpoint
|
|
342
|
-
health_response = requests.get(f"{TB_LOCAL_ADDRESS}/v0/health", timeout=5)
|
|
343
|
-
if health_response.status_code != 200:
|
|
344
|
-
health_check_error["message"] = (
|
|
345
|
-
f"/v0/health endpoint returned status {health_response.status_code}. "
|
|
346
|
-
"Tinybird Local may be unhealthy."
|
|
347
|
-
)
|
|
348
|
-
stop_requested.set()
|
|
349
|
-
break
|
|
350
|
-
|
|
351
|
-
# Verify tokens response has expected structure
|
|
352
|
-
try:
|
|
353
|
-
tokens_data = tokens_response.json()
|
|
354
|
-
if not all(
|
|
355
|
-
key in tokens_data for key in ["user_token", "admin_token", "workspace_admin_token"]
|
|
356
|
-
):
|
|
357
|
-
health_check_error["message"] = (
|
|
358
|
-
"/tokens endpoint returned unexpected data. Tinybird Local may be unhealthy."
|
|
359
|
-
)
|
|
360
|
-
stop_requested.set()
|
|
361
|
-
break
|
|
362
|
-
except json.JSONDecodeError:
|
|
363
|
-
health_check_error["message"] = (
|
|
364
|
-
"/tokens endpoint returned invalid JSON. Tinybird Local may be unhealthy."
|
|
365
|
-
)
|
|
366
|
-
stop_requested.set()
|
|
367
|
-
break
|
|
368
|
-
|
|
369
|
-
except Exception as e:
|
|
370
|
-
# Check if it's a connection error
|
|
371
|
-
error_str = str(e)
|
|
372
|
-
if "connect" in error_str.lower() or "timeout" in error_str.lower():
|
|
373
|
-
health_check_error["message"] = f"Failed to connect to Tinybird Local: {error_str}"
|
|
374
|
-
else:
|
|
375
|
-
health_check_error["message"] = f"Health check failed: {error_str}"
|
|
376
|
-
stop_requested.set()
|
|
377
|
-
break
|
|
378
|
-
|
|
379
|
-
# Wait before next check
|
|
380
|
-
for _ in range(check_interval):
|
|
381
|
-
if stop_requested.is_set():
|
|
382
|
-
break
|
|
383
|
-
time.sleep(1)
|
|
384
|
-
|
|
385
|
-
def stream_logs_with_health_check() -> None:
|
|
386
|
-
"""Stream logs and monitor container health in parallel"""
|
|
387
|
-
log_names = {
|
|
388
|
-
"/var/log/tinybird-local-setup.log": "SETUP",
|
|
389
|
-
"/var/log/tinybird-local-server.log": "SERVER",
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
# Wait briefly for log files to be created
|
|
393
|
-
retry_count = 0
|
|
394
|
-
max_retries = 3
|
|
395
|
-
exec_result = None
|
|
396
|
-
|
|
397
|
-
while retry_count < max_retries and not stop_requested.is_set():
|
|
398
|
-
try:
|
|
399
|
-
# Try to tail the log files (only new logs, not historical)
|
|
400
|
-
# Use -F to follow by name and retry if files don't exist yet
|
|
401
|
-
cmd = ["tail", "-n", "0", "-F", *log_names.keys()]
|
|
402
|
-
exec_result = container.exec_run(cmd=cmd, stream=True, tty=False, stdout=True, stderr=True)
|
|
403
|
-
break # Success, exit retry loop
|
|
404
|
-
except Exception:
|
|
405
|
-
# Log file might not exist yet, wait and retry
|
|
406
|
-
retry_count += 1
|
|
407
|
-
if retry_count < max_retries:
|
|
408
|
-
time.sleep(2)
|
|
409
|
-
|
|
410
|
-
# If we couldn't start tailing, fall back to container logs
|
|
411
|
-
if not exec_result and not stop_requested.is_set():
|
|
412
|
-
try:
|
|
413
|
-
for line in container.logs(stream=True, follow=True):
|
|
414
|
-
if stop_requested.is_set():
|
|
415
|
-
break
|
|
416
|
-
click.echo(line.decode("utf-8").rstrip())
|
|
417
|
-
return
|
|
418
|
-
except Exception:
|
|
419
|
-
return # Silently ignore errors in log streaming
|
|
420
|
-
|
|
421
|
-
# Stream logs continuously
|
|
422
|
-
if exec_result:
|
|
423
|
-
try:
|
|
424
|
-
for line in exec_result.output:
|
|
425
|
-
if stop_requested.is_set():
|
|
426
|
-
break
|
|
427
|
-
|
|
428
|
-
decoded_line = line.decode("utf-8").rstrip()
|
|
429
|
-
|
|
430
|
-
# Skip tail error messages about files not existing yet
|
|
431
|
-
if "tail:" in decoded_line and (
|
|
432
|
-
"cannot open" in decoded_line or "no files remaining" in decoded_line
|
|
433
|
-
):
|
|
434
|
-
continue
|
|
435
|
-
|
|
436
|
-
# Replace file path headers with friendly names
|
|
437
|
-
for file_path, friendly_name in log_names.items():
|
|
438
|
-
log_header = f"==> {file_path} <=="
|
|
439
|
-
if log_header in decoded_line:
|
|
440
|
-
decoded_line = decoded_line.replace(log_header, f"==> {friendly_name} <==")
|
|
441
|
-
|
|
442
|
-
# Print "ready" message when container becomes healthy
|
|
443
|
-
if container_ready.is_set() and not hasattr(stream_logs_with_health_check, "ready_printed"):
|
|
444
|
-
click.echo(FeedbackManager.success(message="✓ Tinybird Local is ready!"))
|
|
445
|
-
click.echo(
|
|
446
|
-
FeedbackManager.highlight(message="» Watching Tinybird Local... (Press Ctrl+C to stop)")
|
|
447
|
-
)
|
|
448
|
-
stream_logs_with_health_check.ready_printed = True # type: ignore
|
|
449
|
-
|
|
450
|
-
click.echo(decoded_line)
|
|
451
|
-
except Exception:
|
|
452
|
-
pass # Silently ignore errors when stream is interrupted
|
|
453
|
-
|
|
454
|
-
log_thread = threading.Thread(target=stream_logs_with_health_check, daemon=True)
|
|
328
|
+
log_thread = threading.Thread(
|
|
329
|
+
target=stream_logs_with_health_check,
|
|
330
|
+
args=(container, container_ready, stop_requested),
|
|
331
|
+
daemon=True,
|
|
332
|
+
)
|
|
455
333
|
log_thread.start()
|
|
456
334
|
|
|
457
|
-
health_check_thread = threading.Thread(
|
|
335
|
+
health_check_thread = threading.Thread(
|
|
336
|
+
target=check_endpoints_health,
|
|
337
|
+
args=(container, docker_client, container_ready, stop_requested, health_check),
|
|
338
|
+
daemon=True,
|
|
339
|
+
)
|
|
458
340
|
health_check_thread.start()
|
|
459
341
|
|
|
460
342
|
# Monitor container health in main thread
|
|
343
|
+
memory_warning_shown = False
|
|
461
344
|
try:
|
|
462
345
|
while True:
|
|
463
346
|
container.reload() # Refresh container attributes
|
|
464
347
|
health = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
348
|
+
if not container_ready.is_set():
|
|
349
|
+
click.echo(FeedbackManager.info(message=f"* Tinybird Local container status: {health}"))
|
|
350
|
+
stats = container_stats(container, docker_client)
|
|
351
|
+
click.echo(f"* {stats}")
|
|
352
|
+
|
|
353
|
+
# Check memory sufficiency
|
|
354
|
+
if not memory_warning_shown:
|
|
355
|
+
is_sufficient, warning_msg = check_memory_sufficient(container, docker_client)
|
|
356
|
+
if not is_sufficient and warning_msg:
|
|
357
|
+
click.echo(FeedbackManager.warning(message=f"△ {warning_msg}"))
|
|
358
|
+
raise CLILocalException(
|
|
359
|
+
FeedbackManager.error(
|
|
360
|
+
message="Tinybird Local is unhealthy. Adjust memory and try again."
|
|
361
|
+
)
|
|
362
|
+
)
|
|
363
|
+
|
|
465
364
|
if health == "healthy":
|
|
365
|
+
click.echo(FeedbackManager.highlight(message="» Checking services..."))
|
|
366
|
+
stats = container_stats(container, docker_client)
|
|
367
|
+
click.echo(FeedbackManager.info(message=f"✓ Tinybird Local container ({stats})"))
|
|
368
|
+
|
|
369
|
+
# Check memory sufficiency before checking services
|
|
370
|
+
if not memory_warning_shown:
|
|
371
|
+
is_sufficient, warning_msg = check_memory_sufficient(container, docker_client)
|
|
372
|
+
if not is_sufficient and warning_msg:
|
|
373
|
+
click.echo(FeedbackManager.warning(message=f"△ {warning_msg}"))
|
|
374
|
+
memory_warning_shown = True
|
|
375
|
+
|
|
376
|
+
if not clickhouse_is_ready(container):
|
|
377
|
+
raise Exception("Clickhouse is not ready.")
|
|
378
|
+
click.echo(FeedbackManager.info(message="✓ Clickhouse"))
|
|
379
|
+
|
|
380
|
+
if not redis_is_ready(container):
|
|
381
|
+
raise Exception("Redis is not ready.")
|
|
382
|
+
click.echo(FeedbackManager.info(message="✓ Redis"))
|
|
383
|
+
|
|
384
|
+
if not server_is_ready(container):
|
|
385
|
+
raise Exception("Server is not ready.")
|
|
386
|
+
click.echo(FeedbackManager.info(message="✓ Server"))
|
|
387
|
+
|
|
388
|
+
if not events_is_ready(container):
|
|
389
|
+
raise Exception("Events is not ready.")
|
|
390
|
+
click.echo(FeedbackManager.info(message="✓ Events"))
|
|
391
|
+
|
|
392
|
+
if not local_authentication_is_ready(container):
|
|
393
|
+
raise Exception("Tinybird Local authentication is not ready.")
|
|
394
|
+
click.echo(FeedbackManager.info(message="✓ Tinybird Local authentication"))
|
|
466
395
|
container_ready.set()
|
|
467
396
|
# Keep monitoring and streaming logs until Ctrl+C or health check failure
|
|
468
397
|
while True:
|
|
469
398
|
# Check if health check detected an error
|
|
470
|
-
if stop_requested.is_set() and
|
|
399
|
+
if stop_requested.is_set() and health_check.get("error"):
|
|
471
400
|
time.sleep(0.5) # Give log thread time to finish printing
|
|
472
|
-
|
|
401
|
+
raise CLILocalException(
|
|
473
402
|
FeedbackManager.error(
|
|
474
|
-
message=f"
|
|
403
|
+
message=f"{health_check.get('error')}\n"
|
|
475
404
|
"Please run `tb local restart` to restart the container."
|
|
476
405
|
)
|
|
477
406
|
)
|
|
@@ -479,31 +408,70 @@ def start_tinybird_local(
|
|
|
479
408
|
time.sleep(1)
|
|
480
409
|
if health == "unhealthy":
|
|
481
410
|
stop_requested.set()
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
411
|
+
# Check if memory might be the cause of unhealthy status
|
|
412
|
+
is_sufficient, warning_msg = check_memory_sufficient(container, docker_client)
|
|
413
|
+
error_msg = "Tinybird Local is unhealthy. Try running `tb local restart` in a few seconds."
|
|
414
|
+
if not is_sufficient and warning_msg:
|
|
415
|
+
error_msg = (
|
|
416
|
+
"Tinybird Local is unhealthy.\nnAfter adjusting memory, try running `tb local restart`."
|
|
485
417
|
)
|
|
486
|
-
)
|
|
418
|
+
raise CLILocalException(FeedbackManager.error(message=error_msg))
|
|
487
419
|
time.sleep(5)
|
|
488
420
|
except KeyboardInterrupt:
|
|
489
421
|
stop_requested.set()
|
|
490
422
|
click.echo(FeedbackManager.highlight(message="» Stopping Tinybird Local..."))
|
|
491
|
-
|
|
492
|
-
|
|
423
|
+
try:
|
|
424
|
+
container.stop()
|
|
425
|
+
click.echo(FeedbackManager.success(message="✓ Tinybird Local stopped."))
|
|
426
|
+
except KeyboardInterrupt:
|
|
427
|
+
click.echo(FeedbackManager.warning(message="⚠ Forced exit. Container may still be running."))
|
|
428
|
+
click.echo(FeedbackManager.info(message=" Run `tb local stop` to stop the container manually."))
|
|
493
429
|
return
|
|
494
430
|
|
|
495
431
|
# Non-watch mode: just wait for container to be healthy
|
|
432
|
+
memory_warning_shown = False
|
|
496
433
|
while True:
|
|
497
434
|
container.reload() # Refresh container attributes
|
|
498
435
|
health = container.attrs.get("State", {}).get("Health", {}).get("Status")
|
|
436
|
+
click.echo(FeedbackManager.info(message=f"* Tinybird Local container status: {health}"))
|
|
437
|
+
stats = container_stats(container, docker_client)
|
|
438
|
+
click.echo(f"* {stats}")
|
|
439
|
+
|
|
440
|
+
# Check memory sufficiency
|
|
441
|
+
if not memory_warning_shown:
|
|
442
|
+
is_sufficient, warning_msg = check_memory_sufficient(container, docker_client)
|
|
443
|
+
if not is_sufficient and warning_msg:
|
|
444
|
+
click.echo(FeedbackManager.warning(message=f"△ {warning_msg}"))
|
|
445
|
+
memory_warning_shown = True
|
|
446
|
+
raise CLILocalException(
|
|
447
|
+
FeedbackManager.error(message="Tinybird Local is unhealthy. Adjust memory and try again.")
|
|
448
|
+
)
|
|
449
|
+
|
|
499
450
|
if health == "healthy":
|
|
451
|
+
click.echo(FeedbackManager.highlight(message="» Checking services..."))
|
|
452
|
+
stats = container_stats(container, docker_client)
|
|
453
|
+
click.echo(FeedbackManager.info(message=f"✓ Tinybird Local container ({stats})"))
|
|
454
|
+
if not clickhouse_is_ready(container):
|
|
455
|
+
raise Exception("Clickhouse is not ready.")
|
|
456
|
+
click.echo(FeedbackManager.info(message="✓ Clickhouse"))
|
|
457
|
+
if not redis_is_ready(container):
|
|
458
|
+
raise Exception("Redis is not ready.")
|
|
459
|
+
click.echo(FeedbackManager.info(message="✓ Redis"))
|
|
460
|
+
if not server_is_ready(container):
|
|
461
|
+
raise Exception("Server is not ready.")
|
|
462
|
+
click.echo(FeedbackManager.info(message="✓ Server"))
|
|
463
|
+
if not events_is_ready(container):
|
|
464
|
+
raise Exception("Events is not ready.")
|
|
465
|
+
click.echo(FeedbackManager.info(message="✓ Events"))
|
|
466
|
+
if not local_authentication_is_ready(container):
|
|
467
|
+
raise Exception("Tinybird Local authentication is not ready.")
|
|
468
|
+
click.echo(FeedbackManager.info(message="✓ Tinybird Local authentication"))
|
|
500
469
|
break
|
|
501
470
|
if health == "unhealthy":
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
)
|
|
471
|
+
# Check if memory might be the cause of unhealthy status
|
|
472
|
+
is_sufficient, warning_msg = check_memory_sufficient(container, docker_client)
|
|
473
|
+
error_msg = "Tinybird Local is unhealthy. Try running `tb local restart` in a few seconds."
|
|
474
|
+
raise CLILocalException(FeedbackManager.error(message=error_msg))
|
|
507
475
|
time.sleep(5)
|
|
508
476
|
|
|
509
477
|
# Remove tinybird-local dangling images to avoid running out of disk space
|
|
@@ -667,3 +635,157 @@ def get_use_aws_creds() -> dict[str, str]:
|
|
|
667
635
|
)
|
|
668
636
|
|
|
669
637
|
return credentials
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
SERVICE_COLORS = {
|
|
641
|
+
"[EVENTS]": "\033[95m", # Magenta
|
|
642
|
+
"[SERVER]": "\033[94m", # Blue
|
|
643
|
+
"[HEALTH]": "\033[96m", # Cyan
|
|
644
|
+
"[KAFKA]": "\033[93m", # Yellow
|
|
645
|
+
"[AUTH]": "\033[90m", # Gray
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
RESET = "\033[0m"
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def check_endpoints_health(
|
|
652
|
+
container: Container,
|
|
653
|
+
docker_client: DockerClient,
|
|
654
|
+
container_ready: threading.Event,
|
|
655
|
+
stop_requested: threading.Event,
|
|
656
|
+
health_check: dict[str, str],
|
|
657
|
+
) -> None:
|
|
658
|
+
"""Continuously check /tokens and /v0/health endpoints"""
|
|
659
|
+
# Wait for container to be ready before starting health checks
|
|
660
|
+
container_ready.wait()
|
|
661
|
+
|
|
662
|
+
# Give container a moment to fully start up
|
|
663
|
+
time.sleep(2)
|
|
664
|
+
|
|
665
|
+
check_interval = 10 # Check every 10 seconds
|
|
666
|
+
|
|
667
|
+
while not stop_requested.is_set():
|
|
668
|
+
try:
|
|
669
|
+
# Check /tokens endpoint
|
|
670
|
+
tokens_response = requests.get(f"{TB_LOCAL_ADDRESS}/tokens", timeout=5)
|
|
671
|
+
if tokens_response.status_code != 200:
|
|
672
|
+
health_check["error"] = (
|
|
673
|
+
f"/tokens endpoint returned status {tokens_response.status_code}. Tinybird Local may be unhealthy."
|
|
674
|
+
)
|
|
675
|
+
stop_requested.set()
|
|
676
|
+
break
|
|
677
|
+
|
|
678
|
+
# Check /v0/health endpoint
|
|
679
|
+
health_response = requests.get(f"{TB_LOCAL_ADDRESS}/v0/health", timeout=5)
|
|
680
|
+
if health_response.status_code != 200:
|
|
681
|
+
health_check["error"] = (
|
|
682
|
+
f"/v0/health endpoint returned status {health_response.status_code}. "
|
|
683
|
+
"Tinybird Local may be unhealthy."
|
|
684
|
+
)
|
|
685
|
+
stop_requested.set()
|
|
686
|
+
break
|
|
687
|
+
|
|
688
|
+
# Verify tokens response has expected structure
|
|
689
|
+
try:
|
|
690
|
+
tokens_data = tokens_response.json()
|
|
691
|
+
if not all(key in tokens_data for key in ["user_token", "admin_token", "workspace_admin_token"]):
|
|
692
|
+
health_check["error"] = (
|
|
693
|
+
"/tokens endpoint returned unexpected data. Tinybird Local may be unhealthy."
|
|
694
|
+
)
|
|
695
|
+
stop_requested.set()
|
|
696
|
+
break
|
|
697
|
+
except json.JSONDecodeError:
|
|
698
|
+
health_check["error"] = "/tokens endpoint returned invalid JSON. Tinybird Local may be unhealthy."
|
|
699
|
+
stop_requested.set()
|
|
700
|
+
break
|
|
701
|
+
|
|
702
|
+
except Exception as e:
|
|
703
|
+
# Check if it's a connection error
|
|
704
|
+
error_str = str(e)
|
|
705
|
+
if "connect" in error_str.lower() or "timeout" in error_str.lower():
|
|
706
|
+
health_check["error"] = f"Failed to connect to Tinybird Local: {error_str}"
|
|
707
|
+
else:
|
|
708
|
+
health_check["error"] = f"Health check failed: {error_str}"
|
|
709
|
+
stop_requested.set()
|
|
710
|
+
break
|
|
711
|
+
|
|
712
|
+
if container_ready.is_set():
|
|
713
|
+
stats = container_stats(container, docker_client)
|
|
714
|
+
click.echo(f"{SERVICE_COLORS['[HEALTH]']}[HEALTH]{RESET} {stats}")
|
|
715
|
+
|
|
716
|
+
# Wait before next check
|
|
717
|
+
for _ in range(check_interval):
|
|
718
|
+
if stop_requested.is_set():
|
|
719
|
+
break
|
|
720
|
+
time.sleep(1)
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
def stream_logs_with_health_check(
|
|
724
|
+
container: Container, container_ready: threading.Event, stop_requested: threading.Event
|
|
725
|
+
) -> None:
|
|
726
|
+
"""Stream logs and monitor container health in parallel"""
|
|
727
|
+
# Wait for container to be ready before starting health checks
|
|
728
|
+
container_ready.wait()
|
|
729
|
+
|
|
730
|
+
# Give container a moment to fully start up
|
|
731
|
+
time.sleep(2)
|
|
732
|
+
|
|
733
|
+
retry_count = 0
|
|
734
|
+
max_retries = 10
|
|
735
|
+
exec_result = None
|
|
736
|
+
|
|
737
|
+
while retry_count < max_retries and not stop_requested.is_set():
|
|
738
|
+
try:
|
|
739
|
+
# Try to tail the log files (only new logs, not historical)
|
|
740
|
+
# Use -F to follow by name and retry if files don't exist yet
|
|
741
|
+
log_files = {
|
|
742
|
+
"/var/log/tinybird-local-server.log": "SERVER",
|
|
743
|
+
"/var/log/tinybird-local-hfi.log": "EVENTS",
|
|
744
|
+
"/var/log/tinybird-local-setup.log": "AUTH",
|
|
745
|
+
"/var/log/tinybird-local-kafka.log": "KAFKA",
|
|
746
|
+
}
|
|
747
|
+
# Build commands to tail each file and prefix with its label (using stdbuf for unbuffered output)
|
|
748
|
+
tail_commands = [
|
|
749
|
+
f'tail -n 0 -f {path} | stdbuf -oL sed "s/^/[{source}] /"' for path, source in log_files.items()
|
|
750
|
+
]
|
|
751
|
+
# Join with & to run in parallel, then wait for all
|
|
752
|
+
cmd = f"sh -c '({' & '.join(tail_commands)}) & wait'"
|
|
753
|
+
exec_result = container.exec_run(cmd, stream=True, tty=False, stdout=True, stderr=True)
|
|
754
|
+
break # Success, exit retry loop
|
|
755
|
+
except Exception:
|
|
756
|
+
# Log file might not exist yet, wait and retry
|
|
757
|
+
retry_count += 1
|
|
758
|
+
if retry_count < max_retries:
|
|
759
|
+
time.sleep(2)
|
|
760
|
+
|
|
761
|
+
# Stream logs continuously
|
|
762
|
+
if exec_result:
|
|
763
|
+
try:
|
|
764
|
+
for line in exec_result.output:
|
|
765
|
+
if stop_requested.is_set():
|
|
766
|
+
break
|
|
767
|
+
|
|
768
|
+
raw_line = line.decode("utf-8").rstrip()
|
|
769
|
+
lines = raw_line.split("\n")
|
|
770
|
+
|
|
771
|
+
# Print "ready" message when container becomes healthy
|
|
772
|
+
if container_ready.is_set() and not hasattr(stream_logs_with_health_check, "ready_printed"):
|
|
773
|
+
click.echo(FeedbackManager.success(message="✓ Tinybird Local is ready!"))
|
|
774
|
+
stream_logs_with_health_check.ready_printed = True # type: ignore
|
|
775
|
+
|
|
776
|
+
for line in lines:
|
|
777
|
+
# Apply color to service label
|
|
778
|
+
for service, color in SERVICE_COLORS.items():
|
|
779
|
+
if line.startswith(service):
|
|
780
|
+
message = line[len(service) :]
|
|
781
|
+
# extract content of message="...""
|
|
782
|
+
match = re.search(r'message="([^"]*)"', message)
|
|
783
|
+
if match:
|
|
784
|
+
message = match.group(1)
|
|
785
|
+
line = f"{color}{service}{RESET} {message}"
|
|
786
|
+
break
|
|
787
|
+
|
|
788
|
+
click.echo(line)
|
|
789
|
+
|
|
790
|
+
except Exception:
|
|
791
|
+
pass # Silently ignore errors when stream is interrupted
|