stemtrace 0.2.1__tar.gz → 0.3.0__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.
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.bumpversion.toml +15 -1
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.github/workflows/e2e.yml +48 -10
- {stemtrace-0.2.1 → stemtrace-0.3.0}/CHANGELOG.md +4 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/Makefile +34 -4
- {stemtrace-0.2.1 → stemtrace-0.3.0}/PKG-INFO +26 -7
- {stemtrace-0.2.1 → stemtrace-0.3.0}/README.md +24 -6
- stemtrace-0.3.0/docker-compose.e2e.rabbitmq.yml +88 -0
- stemtrace-0.3.0/docker-compose.rabbitmq.yml +44 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/pyproject.toml +12 -1
- stemtrace-0.3.0/scripts/wait_for_http.py +41 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/__init__.py +1 -1
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/core/exceptions.py +1 -1
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/transports/__init__.py +5 -0
- stemtrace-0.3.0/src/stemtrace/library/transports/rabbitmq.py +250 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/package.json +1 -1
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/static.py +41 -2
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/e2e/tasks.py +3 -2
- stemtrace-0.3.0/tests/e2e/test_workers_e2e.py +197 -0
- stemtrace-0.3.0/tests/integration/test_rabbitmq_transport.py +139 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/integration/test_static_ui.py +51 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_init.py +9 -3
- stemtrace-0.3.0/tests/unit/test_transports.py +1033 -0
- stemtrace-0.3.0/tests/unit/test_ui_static_prefix.py +61 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/uv.lock +1 -1
- stemtrace-0.2.1/tests/e2e/test_workers_e2e.py +0 -117
- stemtrace-0.2.1/tests/unit/test_transports.py +0 -543
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.dockerignore +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.github/dependabot.yml +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.github/workflows/ci.yml +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.github/workflows/release.yml +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.gitignore +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.pre-commit-config.yaml +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/.python-version +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/CONTRIBUTING.md +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/Dockerfile +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/Dockerfile.e2e +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/LICENSE +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/build_ui.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/docker-compose.e2e.yml +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/docker-compose.yml +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/docs/screenshots/task_details.png +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/docs/screenshots/unregistered.png +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/docs/screenshots/workflow.png +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/examples/celery_app.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/examples/fastapi_integration.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/examples/with_auth.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/progress.md +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/core/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/core/events.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/core/graph.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/core/ports.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/bootsteps.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/config.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/scrubbing.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/signals.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/transports/memory.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/library/transports/redis.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/py.typed +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/__main__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/api/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/api/routes.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/api/schemas.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/api/websocket.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/consumer.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/fastapi/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/fastapi/auth.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/fastapi/extension.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/fastapi/router.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/store.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/biome.json +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/index.html +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/package-lock.json +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/playwright.config.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/postcss.config.js +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/api/client.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/api/queries.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/DateRangePicker.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/Filters.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/TaskGraph.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/TaskList.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/TaskStateBadge.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/TaskTimeline.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/TimelineBar.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/components/Tooltip.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/hooks/WebSocketContext.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/hooks/useInfiniteScroll.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/index.css +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/main.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/routes/__root.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/routes/graph.$rootId.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/routes/graphs.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/routes/index.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/routes/registry.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/routes/tasks.$taskId.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/routes/workers.tsx +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/utils/format.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/src/vite-env.d.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tests/fixtures/mock-api.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tests/fixtures/mock-data.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tests/graphs.spec.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tests/registry.spec.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tests/task-detail.spec.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tests/tasks.spec.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tests/workers.spec.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tsconfig.json +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/tsconfig.tsbuildinfo +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/ui/frontend/vite.config.ts +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/src/stemtrace/server/websocket.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/conftest.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/e2e/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/e2e/conftest.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/e2e/test_api_e2e.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/integration/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/integration/test_embedded_static.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/integration/test_fastapi_integration.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/integration/test_redis_transport.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/integration/test_workers_refresh.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/__init__.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_auth.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_bootsteps.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_config.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_consumer.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_events.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_examples.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_exceptions.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_graph.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_routes.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_scrubbing.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_signals.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_store.py +0 -0
- {stemtrace-0.2.1 → stemtrace-0.3.0}/tests/unit/test_websocket.py +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[tool.bumpversion]
|
|
2
|
-
current_version = "0.
|
|
2
|
+
current_version = "0.3.0"
|
|
3
3
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
|
|
4
4
|
serialize = ["{major}.{minor}.{patch}"]
|
|
5
5
|
commit = true
|
|
@@ -24,6 +24,14 @@ filename = "src/stemtrace/server/ui/frontend/package.json"
|
|
|
24
24
|
search = '"version": "{current_version}"'
|
|
25
25
|
replace = '"version": "{new_version}"'
|
|
26
26
|
|
|
27
|
+
# uv.lock - keep workspace lockfile in sync (uv stores the local project version)
|
|
28
|
+
[[tool.bumpversion.files]]
|
|
29
|
+
filename = "uv.lock"
|
|
30
|
+
search = """name = "stemtrace"
|
|
31
|
+
version = "{current_version}"""
|
|
32
|
+
replace = """name = "stemtrace"
|
|
33
|
+
version = "{new_version}"""
|
|
34
|
+
|
|
27
35
|
# CHANGELOG.md - insert new version header
|
|
28
36
|
[[tool.bumpversion.files]]
|
|
29
37
|
filename = "CHANGELOG.md"
|
|
@@ -31,3 +39,9 @@ search = "## [Unreleased]"
|
|
|
31
39
|
replace = """## [Unreleased]
|
|
32
40
|
|
|
33
41
|
## [{new_version}] - {now:%Y-%m-%d}"""
|
|
42
|
+
|
|
43
|
+
# README.md - keep PyPI badge in sync with version (avoid cached badge drift)
|
|
44
|
+
[[tool.bumpversion.files]]
|
|
45
|
+
filename = "README.md"
|
|
46
|
+
search = "[](https://pypi.org/project/stemtrace)"
|
|
47
|
+
replace = "[](https://pypi.org/project/stemtrace)"
|
|
@@ -13,6 +13,12 @@ jobs:
|
|
|
13
13
|
name: API E2E Tests
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
timeout-minutes: 15
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
broker:
|
|
20
|
+
- redis
|
|
21
|
+
- rabbitmq
|
|
16
22
|
|
|
17
23
|
steps:
|
|
18
24
|
- uses: actions/checkout@v6
|
|
@@ -20,13 +26,25 @@ jobs:
|
|
|
20
26
|
- name: Set up Docker Buildx
|
|
21
27
|
uses: docker/setup-buildx-action@v3
|
|
22
28
|
|
|
29
|
+
- name: Select compose file and Celery env
|
|
30
|
+
run: |
|
|
31
|
+
if [ "${{ matrix.broker }}" = "rabbitmq" ]; then
|
|
32
|
+
echo "COMPOSE_FILE=docker-compose.e2e.rabbitmq.yml" >> "$GITHUB_ENV"
|
|
33
|
+
echo "CELERY_BROKER_URL=amqp://guest:guest@localhost:5672//" >> "$GITHUB_ENV"
|
|
34
|
+
echo "CELERY_RESULT_BACKEND=redis://localhost:16380/1" >> "$GITHUB_ENV"
|
|
35
|
+
else
|
|
36
|
+
echo "COMPOSE_FILE=docker-compose.e2e.yml" >> "$GITHUB_ENV"
|
|
37
|
+
echo "CELERY_BROKER_URL=redis://localhost:16379/0" >> "$GITHUB_ENV"
|
|
38
|
+
echo "CELERY_RESULT_BACKEND=redis://localhost:16379/1" >> "$GITHUB_ENV"
|
|
39
|
+
fi
|
|
40
|
+
|
|
23
41
|
- name: Build images
|
|
24
42
|
run: |
|
|
25
|
-
docker compose -f
|
|
43
|
+
docker compose -f "$COMPOSE_FILE" build
|
|
26
44
|
|
|
27
45
|
- name: Start services
|
|
28
46
|
run: |
|
|
29
|
-
docker compose -f
|
|
47
|
+
docker compose -f "$COMPOSE_FILE" up -d
|
|
30
48
|
# Wait for services to be healthy
|
|
31
49
|
echo "Waiting for services..."
|
|
32
50
|
timeout 120 bash -c 'until curl -sf http://localhost:8000/stemtrace/api/health -o /dev/null; do sleep 2; done'
|
|
@@ -51,16 +69,23 @@ jobs:
|
|
|
51
69
|
- name: Show logs on failure
|
|
52
70
|
if: failure()
|
|
53
71
|
run: |
|
|
54
|
-
docker compose -f
|
|
72
|
+
docker compose -f "$COMPOSE_FILE" logs
|
|
55
73
|
|
|
56
74
|
- name: Stop services
|
|
57
75
|
if: always()
|
|
58
|
-
run:
|
|
76
|
+
run: |
|
|
77
|
+
docker compose -f "$COMPOSE_FILE" down -v
|
|
59
78
|
|
|
60
79
|
playwright:
|
|
61
80
|
name: Playwright E2E Tests
|
|
62
81
|
runs-on: ubuntu-latest
|
|
63
82
|
timeout-minutes: 20
|
|
83
|
+
strategy:
|
|
84
|
+
fail-fast: false
|
|
85
|
+
matrix:
|
|
86
|
+
broker:
|
|
87
|
+
- redis
|
|
88
|
+
- rabbitmq
|
|
64
89
|
|
|
65
90
|
steps:
|
|
66
91
|
- uses: actions/checkout@v6
|
|
@@ -68,13 +93,25 @@ jobs:
|
|
|
68
93
|
- name: Set up Docker Buildx
|
|
69
94
|
uses: docker/setup-buildx-action@v3
|
|
70
95
|
|
|
96
|
+
- name: Select compose file and Celery env
|
|
97
|
+
run: |
|
|
98
|
+
if [ "${{ matrix.broker }}" = "rabbitmq" ]; then
|
|
99
|
+
echo "COMPOSE_FILE=docker-compose.e2e.rabbitmq.yml" >> "$GITHUB_ENV"
|
|
100
|
+
echo "CELERY_BROKER_URL=amqp://guest:guest@localhost:5672//" >> "$GITHUB_ENV"
|
|
101
|
+
echo "CELERY_RESULT_BACKEND=redis://localhost:16380/1" >> "$GITHUB_ENV"
|
|
102
|
+
else
|
|
103
|
+
echo "COMPOSE_FILE=docker-compose.e2e.yml" >> "$GITHUB_ENV"
|
|
104
|
+
echo "CELERY_BROKER_URL=redis://localhost:16379/0" >> "$GITHUB_ENV"
|
|
105
|
+
echo "CELERY_RESULT_BACKEND=redis://localhost:16379/1" >> "$GITHUB_ENV"
|
|
106
|
+
fi
|
|
107
|
+
|
|
71
108
|
- name: Build images
|
|
72
109
|
run: |
|
|
73
|
-
docker compose -f
|
|
110
|
+
docker compose -f "$COMPOSE_FILE" build
|
|
74
111
|
|
|
75
112
|
- name: Start services
|
|
76
113
|
run: |
|
|
77
|
-
docker compose -f
|
|
114
|
+
docker compose -f "$COMPOSE_FILE" up -d
|
|
78
115
|
echo "Waiting for services..."
|
|
79
116
|
timeout 120 bash -c 'until curl -sf http://localhost:8000/stemtrace/api/health -o /dev/null; do sleep 2; done'
|
|
80
117
|
echo "Services ready!"
|
|
@@ -133,7 +170,7 @@ jobs:
|
|
|
133
170
|
uses: actions/upload-artifact@v6
|
|
134
171
|
if: always()
|
|
135
172
|
with:
|
|
136
|
-
name: playwright-report
|
|
173
|
+
name: playwright-report-${{ matrix.broker }}
|
|
137
174
|
path: src/stemtrace/server/ui/frontend/playwright-report/
|
|
138
175
|
retention-days: 7
|
|
139
176
|
|
|
@@ -141,15 +178,16 @@ jobs:
|
|
|
141
178
|
uses: actions/upload-artifact@v6
|
|
142
179
|
if: failure()
|
|
143
180
|
with:
|
|
144
|
-
name: playwright-test-results
|
|
181
|
+
name: playwright-test-results-${{ matrix.broker }}
|
|
145
182
|
path: src/stemtrace/server/ui/frontend/test-results/
|
|
146
183
|
retention-days: 7
|
|
147
184
|
|
|
148
185
|
- name: Show logs on failure
|
|
149
186
|
if: failure()
|
|
150
187
|
run: |
|
|
151
|
-
docker compose -f
|
|
188
|
+
docker compose -f "$COMPOSE_FILE" logs
|
|
152
189
|
|
|
153
190
|
- name: Stop services
|
|
154
191
|
if: always()
|
|
155
|
-
run:
|
|
192
|
+
run: |
|
|
193
|
+
docker compose -f "$COMPOSE_FILE" down -v
|
|
@@ -126,7 +126,7 @@ bump-patch:
|
|
|
126
126
|
@NEW_VER=$$(uv run bump-my-version show current_version); \
|
|
127
127
|
echo "✅ Version bumped to $$NEW_VER"; \
|
|
128
128
|
echo ""; \
|
|
129
|
-
echo "Next:
|
|
129
|
+
echo "Next: make release"
|
|
130
130
|
|
|
131
131
|
# Bump minor version (0.1.0 -> 0.2.0)
|
|
132
132
|
bump-minor:
|
|
@@ -134,7 +134,7 @@ bump-minor:
|
|
|
134
134
|
@NEW_VER=$$(uv run bump-my-version show current_version); \
|
|
135
135
|
echo "✅ Version bumped to $$NEW_VER"; \
|
|
136
136
|
echo ""; \
|
|
137
|
-
echo "Next:
|
|
137
|
+
echo "Next: make release"
|
|
138
138
|
|
|
139
139
|
# Bump major version (0.1.0 -> 1.0.0)
|
|
140
140
|
bump-major:
|
|
@@ -142,7 +142,7 @@ bump-major:
|
|
|
142
142
|
@NEW_VER=$$(uv run bump-my-version show current_version); \
|
|
143
143
|
echo "✅ Version bumped to $$NEW_VER"; \
|
|
144
144
|
echo ""; \
|
|
145
|
-
echo "Next:
|
|
145
|
+
echo "Next: make release"
|
|
146
146
|
|
|
147
147
|
# Tag and push to trigger release workflow
|
|
148
148
|
release:
|
|
@@ -168,9 +168,10 @@ e2e-mock:
|
|
|
168
168
|
|
|
169
169
|
# Start E2E test environment (Docker)
|
|
170
170
|
e2e-up:
|
|
171
|
+
docker compose -f docker-compose.e2e.yml build
|
|
171
172
|
docker compose -f docker-compose.e2e.yml up -d --wait
|
|
172
173
|
@echo "Waiting for services..."
|
|
173
|
-
@
|
|
174
|
+
@uv run python scripts/wait_for_http.py http://localhost:8000/stemtrace/api/health --timeout 60
|
|
174
175
|
@echo "✅ E2E environment ready at http://localhost:8000"
|
|
175
176
|
|
|
176
177
|
# Stop E2E test environment
|
|
@@ -193,5 +194,34 @@ e2e:
|
|
|
193
194
|
$(MAKE) e2e-down; \
|
|
194
195
|
exit $$status
|
|
195
196
|
|
|
197
|
+
# =============================================================================
|
|
198
|
+
# E2E Testing (RabbitMQ broker)
|
|
199
|
+
# =============================================================================
|
|
200
|
+
|
|
201
|
+
e2e-up-rabbitmq:
|
|
202
|
+
docker compose -f docker-compose.e2e.rabbitmq.yml build
|
|
203
|
+
docker compose -f docker-compose.e2e.rabbitmq.yml up -d --wait
|
|
204
|
+
@echo "Waiting for services..."
|
|
205
|
+
@uv run python scripts/wait_for_http.py http://localhost:8000/stemtrace/api/health --timeout 60
|
|
206
|
+
@echo "✅ RabbitMQ E2E environment ready at http://localhost:8000"
|
|
207
|
+
|
|
208
|
+
e2e-down-rabbitmq:
|
|
209
|
+
docker compose -f docker-compose.e2e.rabbitmq.yml down -v
|
|
210
|
+
|
|
211
|
+
e2e-api-rabbitmq:
|
|
212
|
+
CELERY_BROKER_URL=amqp://guest:guest@localhost:5672// \
|
|
213
|
+
CELERY_RESULT_BACKEND=redis://localhost:16380/1 \
|
|
214
|
+
uv run pytest tests/e2e/ -m e2e -v
|
|
215
|
+
|
|
216
|
+
e2e-playwright-real-rabbitmq:
|
|
217
|
+
cd $(FRONTEND_DIR) && E2E_MODE=real PLAYWRIGHT_BASE_URL=http://localhost:8000 npm test
|
|
218
|
+
|
|
219
|
+
e2e-rabbitmq:
|
|
220
|
+
$(MAKE) e2e-up-rabbitmq
|
|
221
|
+
$(MAKE) e2e-api-rabbitmq && $(MAKE) e2e-playwright-real-rabbitmq; \
|
|
222
|
+
status=$$?; \
|
|
223
|
+
$(MAKE) e2e-down-rabbitmq; \
|
|
224
|
+
exit $$status
|
|
225
|
+
|
|
196
226
|
# Quick E2E alias (mock mode, no Docker)
|
|
197
227
|
e2e-quick: e2e-mock
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stemtrace
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A lightweight Celery task flow visualizer
|
|
5
5
|
Project-URL: Homepage, https://github.com/iansokolskyi/stemtrace
|
|
6
6
|
Project-URL: Documentation, https://github.com/iansokolskyi/stemtrace#readme
|
|
@@ -8,6 +8,7 @@ Project-URL: Repository, https://github.com/iansokolskyi/stemtrace
|
|
|
8
8
|
Project-URL: Issues, https://github.com/iansokolskyi/stemtrace/issues
|
|
9
9
|
Project-URL: Changelog, https://github.com/iansokolskyi/stemtrace/blob/main/CHANGELOG.md
|
|
10
10
|
Author-email: Ian Sokolskyi <iansokolskyi@gmail.com>
|
|
11
|
+
Maintainer-email: Ian Sokolskyi <iansokolskyi@gmail.com>
|
|
11
12
|
License: MIT
|
|
12
13
|
License-File: LICENSE
|
|
13
14
|
Keywords: celery,monitoring,queue,task,visualization,workflow
|
|
@@ -55,7 +56,7 @@ Description-Content-Type: text/markdown
|
|
|
55
56
|
|
|
56
57
|
**Zero-infrastructure Celery task flow visualizer**
|
|
57
58
|
|
|
58
|
-
[](https://pypi.org/project/stemtrace)
|
|
59
60
|
[](https://pypi.org/project/stemtrace/)
|
|
60
61
|
[](https://github.com/iansokolskyi/stemtrace/actions/workflows/ci.yml)
|
|
61
62
|
[](https://codecov.io/gh/iansokolskyi/stemtrace)
|
|
@@ -71,7 +72,7 @@ Ever stared at a failed Celery task wondering "what called this?" or "why did it
|
|
|
71
72
|
|
|
72
73
|
Stemtrace captures your task executions as a graph — visualize parent→child flows, see retry chains, track groups and chords, all without adding any new infrastructure.
|
|
73
74
|
|
|
74
|
-
**
|
|
75
|
+
**stemtrace supports Redis and RabbitMQ** for event transport.
|
|
75
76
|
|
|
76
77
|
## ✨ Features
|
|
77
78
|
|
|
@@ -90,7 +91,7 @@ Stemtrace captures your task executions as a graph — visualize parent→child
|
|
|
90
91
|
- **Registry status badges** — Quickly spot tasks that are active, never run, or not registered by any current worker
|
|
91
92
|
|
|
92
93
|
**Production Ready**
|
|
93
|
-
- **Zero Infrastructure** — Uses your existing Redis
|
|
94
|
+
- **Zero Infrastructure** — Uses your existing broker (Redis or RabbitMQ), no database needed
|
|
94
95
|
- **Sensitive Data Scrubbing** — Passwords and API keys filtered automatically
|
|
95
96
|
- **Read-Only** — Safe for production; never modifies your task queue
|
|
96
97
|
- **FastAPI Integration** — Mount into your existing app with one line
|
|
@@ -161,6 +162,14 @@ stemtrace server
|
|
|
161
162
|
|
|
162
163
|
Open [http://localhost:8000](http://localhost:8000).
|
|
163
164
|
|
|
165
|
+
Tip: make sure the server is pointed at the same broker as your workers:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
stemtrace server --broker-url redis://localhost:6379/0
|
|
169
|
+
# or:
|
|
170
|
+
stemtrace server --broker-url amqp://guest:guest@localhost:5672//
|
|
171
|
+
```
|
|
172
|
+
|
|
164
173
|
**Option B: Embed in your FastAPI app** (no extra container)
|
|
165
174
|
|
|
166
175
|
```python
|
|
@@ -174,7 +183,7 @@ stemtrace.init_app(app, broker_url="redis://localhost:6379/0")
|
|
|
174
183
|
|
|
175
184
|
Access at `/stemtrace/` in your existing app — no new services to deploy.
|
|
176
185
|
|
|
177
|
-
See [Deployment Options](
|
|
186
|
+
See [Deployment Options](#deployment-options) for auth, scaling, and more.
|
|
178
187
|
|
|
179
188
|
## 📦 Architecture
|
|
180
189
|
|
|
@@ -304,7 +313,7 @@ batch_processor
|
|
|
304
313
|
| Broker | URL Scheme | Status |
|
|
305
314
|
|--------|------------|--------|
|
|
306
315
|
| Redis | `redis://`, `rediss://` | ✅ Supported |
|
|
307
|
-
| RabbitMQ | `amqp://`, `amqps://` |
|
|
316
|
+
| RabbitMQ | `amqp://`, `amqps://`, `pyamqp://` | ✅ Supported |
|
|
308
317
|
|
|
309
318
|
## 🐳 Docker
|
|
310
319
|
|
|
@@ -314,6 +323,14 @@ docker run -p 8000:8000 \
|
|
|
314
323
|
ghcr.io/iansokolskyi/stemtrace
|
|
315
324
|
```
|
|
316
325
|
|
|
326
|
+
RabbitMQ example:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
docker run -p 8000:8000 \
|
|
330
|
+
-e STEMTRACE_BROKER_URL=amqp://guest:guest@host.docker.internal:5672// \
|
|
331
|
+
ghcr.io/iansokolskyi/stemtrace
|
|
332
|
+
```
|
|
333
|
+
|
|
317
334
|
Or with Docker Compose:
|
|
318
335
|
|
|
319
336
|
```yaml
|
|
@@ -326,6 +343,8 @@ services:
|
|
|
326
343
|
- STEMTRACE_BROKER_URL=redis://redis:6379/0
|
|
327
344
|
```
|
|
328
345
|
|
|
346
|
+
For a local RabbitMQ setup, see [`docker-compose.rabbitmq.yml`](docker-compose.rabbitmq.yml).
|
|
347
|
+
|
|
329
348
|
## 🖥️ Deployment Options
|
|
330
349
|
|
|
331
350
|
`stemtrace` offers two deployment modes depending on your needs:
|
|
@@ -436,12 +455,12 @@ stemtrace.init_app(
|
|
|
436
455
|
- ✅ **Sensitive data scrubbing** — Passwords and API keys filtered automatically
|
|
437
456
|
- ✅ **Real-time updates** — WebSocket-powered live dashboard
|
|
438
457
|
- ✅ **FastAPI integration** — Mount into your existing app
|
|
458
|
+
- ✅ **RabbitMQ support** — Use your existing RabbitMQ broker (`amqp://`, `amqps://`, `pyamqp://`)
|
|
439
459
|
- ✅ **Workers page** — Monitor online/offline workers and their registered tasks
|
|
440
460
|
- ✅ **Task registry** — Browse discovered + registered tasks with clear status badges
|
|
441
461
|
|
|
442
462
|
### Coming Soon
|
|
443
463
|
|
|
444
|
-
- 🔜 **RabbitMQ support** — Use your existing RabbitMQ broker
|
|
445
464
|
- 🔜 **Anomaly detection** — Spot stuck, orphaned, or failed tasks
|
|
446
465
|
- 🔜 **Dashboard with stats** — Success rates, durations, failure trends
|
|
447
466
|
- 🔜 **OpenTelemetry export** — Send traces to Jaeger, Tempo, Datadog
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Zero-infrastructure Celery task flow visualizer**
|
|
4
4
|
|
|
5
|
-
[](https://pypi.org/project/stemtrace)
|
|
6
6
|
[](https://pypi.org/project/stemtrace/)
|
|
7
7
|
[](https://github.com/iansokolskyi/stemtrace/actions/workflows/ci.yml)
|
|
8
8
|
[](https://codecov.io/gh/iansokolskyi/stemtrace)
|
|
@@ -18,7 +18,7 @@ Ever stared at a failed Celery task wondering "what called this?" or "why did it
|
|
|
18
18
|
|
|
19
19
|
Stemtrace captures your task executions as a graph — visualize parent→child flows, see retry chains, track groups and chords, all without adding any new infrastructure.
|
|
20
20
|
|
|
21
|
-
**
|
|
21
|
+
**stemtrace supports Redis and RabbitMQ** for event transport.
|
|
22
22
|
|
|
23
23
|
## ✨ Features
|
|
24
24
|
|
|
@@ -37,7 +37,7 @@ Stemtrace captures your task executions as a graph — visualize parent→child
|
|
|
37
37
|
- **Registry status badges** — Quickly spot tasks that are active, never run, or not registered by any current worker
|
|
38
38
|
|
|
39
39
|
**Production Ready**
|
|
40
|
-
- **Zero Infrastructure** — Uses your existing Redis
|
|
40
|
+
- **Zero Infrastructure** — Uses your existing broker (Redis or RabbitMQ), no database needed
|
|
41
41
|
- **Sensitive Data Scrubbing** — Passwords and API keys filtered automatically
|
|
42
42
|
- **Read-Only** — Safe for production; never modifies your task queue
|
|
43
43
|
- **FastAPI Integration** — Mount into your existing app with one line
|
|
@@ -108,6 +108,14 @@ stemtrace server
|
|
|
108
108
|
|
|
109
109
|
Open [http://localhost:8000](http://localhost:8000).
|
|
110
110
|
|
|
111
|
+
Tip: make sure the server is pointed at the same broker as your workers:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
stemtrace server --broker-url redis://localhost:6379/0
|
|
115
|
+
# or:
|
|
116
|
+
stemtrace server --broker-url amqp://guest:guest@localhost:5672//
|
|
117
|
+
```
|
|
118
|
+
|
|
111
119
|
**Option B: Embed in your FastAPI app** (no extra container)
|
|
112
120
|
|
|
113
121
|
```python
|
|
@@ -121,7 +129,7 @@ stemtrace.init_app(app, broker_url="redis://localhost:6379/0")
|
|
|
121
129
|
|
|
122
130
|
Access at `/stemtrace/` in your existing app — no new services to deploy.
|
|
123
131
|
|
|
124
|
-
See [Deployment Options](
|
|
132
|
+
See [Deployment Options](#deployment-options) for auth, scaling, and more.
|
|
125
133
|
|
|
126
134
|
## 📦 Architecture
|
|
127
135
|
|
|
@@ -251,7 +259,7 @@ batch_processor
|
|
|
251
259
|
| Broker | URL Scheme | Status |
|
|
252
260
|
|--------|------------|--------|
|
|
253
261
|
| Redis | `redis://`, `rediss://` | ✅ Supported |
|
|
254
|
-
| RabbitMQ | `amqp://`, `amqps://` |
|
|
262
|
+
| RabbitMQ | `amqp://`, `amqps://`, `pyamqp://` | ✅ Supported |
|
|
255
263
|
|
|
256
264
|
## 🐳 Docker
|
|
257
265
|
|
|
@@ -261,6 +269,14 @@ docker run -p 8000:8000 \
|
|
|
261
269
|
ghcr.io/iansokolskyi/stemtrace
|
|
262
270
|
```
|
|
263
271
|
|
|
272
|
+
RabbitMQ example:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
docker run -p 8000:8000 \
|
|
276
|
+
-e STEMTRACE_BROKER_URL=amqp://guest:guest@host.docker.internal:5672// \
|
|
277
|
+
ghcr.io/iansokolskyi/stemtrace
|
|
278
|
+
```
|
|
279
|
+
|
|
264
280
|
Or with Docker Compose:
|
|
265
281
|
|
|
266
282
|
```yaml
|
|
@@ -273,6 +289,8 @@ services:
|
|
|
273
289
|
- STEMTRACE_BROKER_URL=redis://redis:6379/0
|
|
274
290
|
```
|
|
275
291
|
|
|
292
|
+
For a local RabbitMQ setup, see [`docker-compose.rabbitmq.yml`](docker-compose.rabbitmq.yml).
|
|
293
|
+
|
|
276
294
|
## 🖥️ Deployment Options
|
|
277
295
|
|
|
278
296
|
`stemtrace` offers two deployment modes depending on your needs:
|
|
@@ -383,12 +401,12 @@ stemtrace.init_app(
|
|
|
383
401
|
- ✅ **Sensitive data scrubbing** — Passwords and API keys filtered automatically
|
|
384
402
|
- ✅ **Real-time updates** — WebSocket-powered live dashboard
|
|
385
403
|
- ✅ **FastAPI integration** — Mount into your existing app
|
|
404
|
+
- ✅ **RabbitMQ support** — Use your existing RabbitMQ broker (`amqp://`, `amqps://`, `pyamqp://`)
|
|
386
405
|
- ✅ **Workers page** — Monitor online/offline workers and their registered tasks
|
|
387
406
|
- ✅ **Task registry** — Browse discovered + registered tasks with clear status badges
|
|
388
407
|
|
|
389
408
|
### Coming Soon
|
|
390
409
|
|
|
391
|
-
- 🔜 **RabbitMQ support** — Use your existing RabbitMQ broker
|
|
392
410
|
- 🔜 **Anomaly detection** — Spot stuck, orphaned, or failed tasks
|
|
393
411
|
- 🔜 **Dashboard with stats** — Success rates, durations, failure trends
|
|
394
412
|
- 🔜 **OpenTelemetry export** — Send traces to Jaeger, Tempo, Datadog
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Docker Compose for stemtrace E2E testing (RabbitMQ broker)
|
|
2
|
+
#
|
|
3
|
+
# Usage:
|
|
4
|
+
# docker compose -f docker-compose.e2e.rabbitmq.yml up -d --wait
|
|
5
|
+
# docker compose -f docker-compose.e2e.rabbitmq.yml down -v
|
|
6
|
+
#
|
|
7
|
+
# Services:
|
|
8
|
+
# - rabbitmq: RabbitMQ broker (with management UI)
|
|
9
|
+
# - worker: Celery worker running E2E test tasks
|
|
10
|
+
# - server: stemtrace server with UI and API
|
|
11
|
+
|
|
12
|
+
services:
|
|
13
|
+
rabbitmq:
|
|
14
|
+
image: rabbitmq:3-management
|
|
15
|
+
ports:
|
|
16
|
+
- "5672:5672"
|
|
17
|
+
- "15672:15672"
|
|
18
|
+
healthcheck:
|
|
19
|
+
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
|
20
|
+
interval: 2s
|
|
21
|
+
timeout: 5s
|
|
22
|
+
retries: 20
|
|
23
|
+
|
|
24
|
+
redis:
|
|
25
|
+
image: redis:7-alpine
|
|
26
|
+
ports:
|
|
27
|
+
- "16380:6379" # Dedicated port for RabbitMQ E2E result backend
|
|
28
|
+
healthcheck:
|
|
29
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
30
|
+
interval: 2s
|
|
31
|
+
timeout: 2s
|
|
32
|
+
retries: 10
|
|
33
|
+
|
|
34
|
+
worker:
|
|
35
|
+
build:
|
|
36
|
+
context: .
|
|
37
|
+
dockerfile: Dockerfile.e2e
|
|
38
|
+
environment:
|
|
39
|
+
- CELERY_BROKER_URL=amqp://guest:guest@rabbitmq:5672//
|
|
40
|
+
# Redis result backend required for group->callback workflows (Celery upgrades
|
|
41
|
+
# chain(group(...), callback) to a chord, which rpc:// does not support).
|
|
42
|
+
- CELERY_RESULT_BACKEND=redis://redis:6379/1
|
|
43
|
+
depends_on:
|
|
44
|
+
rabbitmq:
|
|
45
|
+
condition: service_healthy
|
|
46
|
+
redis:
|
|
47
|
+
condition: service_healthy
|
|
48
|
+
command: ["celery", "-A", "tests.e2e.tasks", "worker", "--loglevel=info", "--concurrency=2", "-E"]
|
|
49
|
+
healthcheck:
|
|
50
|
+
test: ["CMD", "celery", "-A", "tests.e2e.tasks", "inspect", "ping"]
|
|
51
|
+
interval: 5s
|
|
52
|
+
timeout: 10s
|
|
53
|
+
retries: 10
|
|
54
|
+
start_period: 10s
|
|
55
|
+
|
|
56
|
+
server:
|
|
57
|
+
build:
|
|
58
|
+
context: .
|
|
59
|
+
dockerfile: Dockerfile
|
|
60
|
+
ports:
|
|
61
|
+
- "8000:8000"
|
|
62
|
+
environment:
|
|
63
|
+
- STEMTRACE_BROKER_URL=amqp://guest:guest@rabbitmq:5672//
|
|
64
|
+
depends_on:
|
|
65
|
+
rabbitmq:
|
|
66
|
+
condition: service_healthy
|
|
67
|
+
command:
|
|
68
|
+
[
|
|
69
|
+
"server",
|
|
70
|
+
"--broker-url",
|
|
71
|
+
"amqp://guest:guest@rabbitmq:5672//",
|
|
72
|
+
"--host",
|
|
73
|
+
"0.0.0.0",
|
|
74
|
+
"--port",
|
|
75
|
+
"8000",
|
|
76
|
+
]
|
|
77
|
+
healthcheck:
|
|
78
|
+
test:
|
|
79
|
+
[
|
|
80
|
+
"CMD",
|
|
81
|
+
"python",
|
|
82
|
+
"-c",
|
|
83
|
+
"import httpx; httpx.get('http://localhost:8000/stemtrace/api/health').raise_for_status()",
|
|
84
|
+
]
|
|
85
|
+
interval: 5s
|
|
86
|
+
timeout: 10s
|
|
87
|
+
retries: 10
|
|
88
|
+
start_period: 5s
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Docker Compose for stemtrace with RabbitMQ
|
|
2
|
+
#
|
|
3
|
+
# Usage:
|
|
4
|
+
# docker compose -f docker-compose.rabbitmq.yml up -d
|
|
5
|
+
# docker compose -f docker-compose.rabbitmq.yml logs -f server
|
|
6
|
+
# docker compose -f docker-compose.rabbitmq.yml down
|
|
7
|
+
#
|
|
8
|
+
# Access:
|
|
9
|
+
# - stemtrace UI: http://localhost:8000
|
|
10
|
+
# - RabbitMQ management UI: http://localhost:15672 (guest/guest)
|
|
11
|
+
|
|
12
|
+
services:
|
|
13
|
+
rabbitmq:
|
|
14
|
+
image: rabbitmq:3-management
|
|
15
|
+
ports:
|
|
16
|
+
- "5672:5672"
|
|
17
|
+
- "15672:15672"
|
|
18
|
+
healthcheck:
|
|
19
|
+
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
|
20
|
+
interval: 5s
|
|
21
|
+
timeout: 5s
|
|
22
|
+
retries: 10
|
|
23
|
+
|
|
24
|
+
server:
|
|
25
|
+
build:
|
|
26
|
+
context: .
|
|
27
|
+
dockerfile: Dockerfile
|
|
28
|
+
ports:
|
|
29
|
+
- "8000:8000"
|
|
30
|
+
environment:
|
|
31
|
+
- STEMTRACE_BROKER_URL=amqp://guest:guest@rabbitmq:5672//
|
|
32
|
+
depends_on:
|
|
33
|
+
rabbitmq:
|
|
34
|
+
condition: service_healthy
|
|
35
|
+
command:
|
|
36
|
+
[
|
|
37
|
+
"server",
|
|
38
|
+
"--broker-url",
|
|
39
|
+
"amqp://guest:guest@rabbitmq:5672//",
|
|
40
|
+
"--host",
|
|
41
|
+
"0.0.0.0",
|
|
42
|
+
"--port",
|
|
43
|
+
"8000",
|
|
44
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "stemtrace"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "A lightweight Celery task flow visualizer"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -8,6 +8,9 @@ requires-python = ">=3.10"
|
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "Ian Sokolskyi", email = "iansokolskyi@gmail.com" },
|
|
10
10
|
]
|
|
11
|
+
maintainers = [
|
|
12
|
+
{ name = "Ian Sokolskyi", email = "iansokolskyi@gmail.com" },
|
|
13
|
+
]
|
|
11
14
|
keywords = ["celery", "task", "queue", "visualization", "monitoring", "workflow"]
|
|
12
15
|
classifiers = [
|
|
13
16
|
"Development Status :: 3 - Alpha",
|
|
@@ -106,6 +109,14 @@ ignore_missing_imports = true
|
|
|
106
109
|
module = "typer.*"
|
|
107
110
|
ignore_missing_imports = true
|
|
108
111
|
|
|
112
|
+
[[tool.mypy.overrides]]
|
|
113
|
+
module = "kombu.*"
|
|
114
|
+
ignore_missing_imports = true
|
|
115
|
+
|
|
116
|
+
[[tool.mypy.overrides]]
|
|
117
|
+
module = "amqp.*"
|
|
118
|
+
ignore_missing_imports = true
|
|
119
|
+
|
|
109
120
|
# =============================================================================
|
|
110
121
|
# ruff
|
|
111
122
|
# =============================================================================
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Wait for an HTTP endpoint to respond with a 2xx status."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import time
|
|
7
|
+
import urllib.error
|
|
8
|
+
import urllib.request
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _parse_args() -> argparse.Namespace:
|
|
12
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
13
|
+
parser.add_argument("url")
|
|
14
|
+
parser.add_argument("--timeout", type=float, default=60.0)
|
|
15
|
+
parser.add_argument("--interval", type=float, default=2.0)
|
|
16
|
+
return parser.parse_args()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main() -> None:
|
|
20
|
+
"""Wait for an HTTP endpoint to become healthy (2xx) or exit non-zero."""
|
|
21
|
+
args = _parse_args()
|
|
22
|
+
deadline = time.monotonic() + args.timeout
|
|
23
|
+
last_error: str | None = None
|
|
24
|
+
|
|
25
|
+
while time.monotonic() < deadline:
|
|
26
|
+
try:
|
|
27
|
+
request = urllib.request.Request(args.url, method="GET")
|
|
28
|
+
with urllib.request.urlopen(request, timeout=2.0) as response:
|
|
29
|
+
if 200 <= response.status < 300:
|
|
30
|
+
return
|
|
31
|
+
last_error = f"HTTP {response.status}"
|
|
32
|
+
except (urllib.error.URLError, TimeoutError) as exc:
|
|
33
|
+
last_error = str(exc)
|
|
34
|
+
|
|
35
|
+
time.sleep(args.interval)
|
|
36
|
+
|
|
37
|
+
raise SystemExit(f"Service not healthy within {args.timeout}s: {last_error}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|