stemtrace 0.2.2__tar.gz → 0.3.1__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.
Files changed (145) hide show
  1. {stemtrace-0.2.2 → stemtrace-0.3.1}/.bumpversion.toml +1 -1
  2. {stemtrace-0.2.2 → stemtrace-0.3.1}/.github/workflows/e2e.yml +48 -10
  3. {stemtrace-0.2.2 → stemtrace-0.3.1}/CHANGELOG.md +39 -1
  4. {stemtrace-0.2.2 → stemtrace-0.3.1}/Makefile +31 -1
  5. {stemtrace-0.2.2 → stemtrace-0.3.1}/PKG-INFO +110 -10
  6. {stemtrace-0.2.2 → stemtrace-0.3.1}/README.md +109 -9
  7. stemtrace-0.3.1/docker-compose.e2e.rabbitmq.yml +88 -0
  8. stemtrace-0.3.1/docker-compose.rabbitmq.yml +44 -0
  9. {stemtrace-0.2.2 → stemtrace-0.3.1}/docker-compose.yml +1 -1
  10. {stemtrace-0.2.2 → stemtrace-0.3.1}/examples/celery_app.py +35 -5
  11. {stemtrace-0.2.2 → stemtrace-0.3.1}/examples/fastapi_integration.py +7 -11
  12. {stemtrace-0.2.2 → stemtrace-0.3.1}/examples/with_auth.py +2 -3
  13. stemtrace-0.3.1/examples/with_login.py +43 -0
  14. {stemtrace-0.2.2 → stemtrace-0.3.1}/pyproject.toml +10 -1
  15. stemtrace-0.3.1/scripts/wait_for_http.py +41 -0
  16. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/__init__.py +112 -2
  17. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/core/exceptions.py +1 -1
  18. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/transports/__init__.py +5 -0
  19. stemtrace-0.3.1/src/stemtrace/library/transports/rabbitmq.py +250 -0
  20. stemtrace-0.3.1/src/stemtrace/server/__main__.py +250 -0
  21. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/api/routes.py +195 -29
  22. stemtrace-0.3.1/src/stemtrace/server/api/websocket.py +49 -0
  23. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/fastapi/extension.py +33 -3
  24. stemtrace-0.3.1/src/stemtrace/server/fastapi/form_auth.py +157 -0
  25. stemtrace-0.3.1/src/stemtrace/server/fastapi/login_routes.py +157 -0
  26. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/fastapi/router.py +3 -1
  27. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/package.json +1 -1
  28. stemtrace-0.3.1/src/stemtrace/server/ui/static.py +261 -0
  29. stemtrace-0.3.1/src/stemtrace/server/ui/templates/login.html +153 -0
  30. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/e2e/tasks.py +3 -2
  31. stemtrace-0.3.1/tests/e2e/test_workers_e2e.py +197 -0
  32. stemtrace-0.3.1/tests/integration/test_rabbitmq_transport.py +139 -0
  33. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/integration/test_static_ui.py +51 -0
  34. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/integration/test_workers_refresh.py +1 -1
  35. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_examples.py +50 -2
  36. stemtrace-0.3.1/tests/unit/test_form_auth.py +135 -0
  37. stemtrace-0.3.1/tests/unit/test_form_login.py +169 -0
  38. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_init.py +94 -0
  39. stemtrace-0.3.1/tests/unit/test_routes.py +1186 -0
  40. stemtrace-0.3.1/tests/unit/test_transports.py +1033 -0
  41. stemtrace-0.3.1/tests/unit/test_ui_static_prefix.py +74 -0
  42. {stemtrace-0.2.2 → stemtrace-0.3.1}/uv.lock +1 -1
  43. stemtrace-0.2.2/src/stemtrace/server/__main__.py +0 -136
  44. stemtrace-0.2.2/src/stemtrace/server/api/websocket.py +0 -28
  45. stemtrace-0.2.2/src/stemtrace/server/ui/static.py +0 -122
  46. stemtrace-0.2.2/tests/e2e/test_workers_e2e.py +0 -117
  47. stemtrace-0.2.2/tests/unit/test_routes.py +0 -575
  48. stemtrace-0.2.2/tests/unit/test_transports.py +0 -543
  49. {stemtrace-0.2.2 → stemtrace-0.3.1}/.dockerignore +0 -0
  50. {stemtrace-0.2.2 → stemtrace-0.3.1}/.github/dependabot.yml +0 -0
  51. {stemtrace-0.2.2 → stemtrace-0.3.1}/.github/workflows/ci.yml +0 -0
  52. {stemtrace-0.2.2 → stemtrace-0.3.1}/.github/workflows/release.yml +0 -0
  53. {stemtrace-0.2.2 → stemtrace-0.3.1}/.gitignore +0 -0
  54. {stemtrace-0.2.2 → stemtrace-0.3.1}/.pre-commit-config.yaml +0 -0
  55. {stemtrace-0.2.2 → stemtrace-0.3.1}/.python-version +0 -0
  56. {stemtrace-0.2.2 → stemtrace-0.3.1}/CONTRIBUTING.md +0 -0
  57. {stemtrace-0.2.2 → stemtrace-0.3.1}/Dockerfile +0 -0
  58. {stemtrace-0.2.2 → stemtrace-0.3.1}/Dockerfile.e2e +0 -0
  59. {stemtrace-0.2.2 → stemtrace-0.3.1}/LICENSE +0 -0
  60. {stemtrace-0.2.2 → stemtrace-0.3.1}/build_ui.py +0 -0
  61. {stemtrace-0.2.2 → stemtrace-0.3.1}/docker-compose.e2e.yml +0 -0
  62. {stemtrace-0.2.2 → stemtrace-0.3.1}/docs/screenshots/task_details.png +0 -0
  63. {stemtrace-0.2.2 → stemtrace-0.3.1}/docs/screenshots/unregistered.png +0 -0
  64. {stemtrace-0.2.2 → stemtrace-0.3.1}/docs/screenshots/workflow.png +0 -0
  65. {stemtrace-0.2.2 → stemtrace-0.3.1}/progress.md +0 -0
  66. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/core/__init__.py +0 -0
  67. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/core/events.py +0 -0
  68. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/core/graph.py +0 -0
  69. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/core/ports.py +0 -0
  70. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/__init__.py +0 -0
  71. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/bootsteps.py +0 -0
  72. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/config.py +0 -0
  73. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/scrubbing.py +0 -0
  74. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/signals.py +0 -0
  75. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/transports/memory.py +0 -0
  76. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/library/transports/redis.py +0 -0
  77. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/py.typed +0 -0
  78. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/__init__.py +0 -0
  79. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/api/__init__.py +0 -0
  80. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/api/schemas.py +0 -0
  81. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/consumer.py +0 -0
  82. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/fastapi/__init__.py +0 -0
  83. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/fastapi/auth.py +0 -0
  84. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/store.py +0 -0
  85. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/__init__.py +0 -0
  86. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/biome.json +0 -0
  87. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/index.html +0 -0
  88. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/package-lock.json +0 -0
  89. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/playwright.config.ts +0 -0
  90. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/postcss.config.js +0 -0
  91. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/api/client.ts +0 -0
  92. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/api/queries.ts +0 -0
  93. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/DateRangePicker.tsx +0 -0
  94. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/Filters.tsx +0 -0
  95. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/TaskGraph.tsx +0 -0
  96. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/TaskList.tsx +0 -0
  97. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/TaskStateBadge.tsx +0 -0
  98. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/TaskTimeline.tsx +0 -0
  99. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/TimelineBar.tsx +0 -0
  100. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/components/Tooltip.tsx +0 -0
  101. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/hooks/WebSocketContext.tsx +0 -0
  102. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/hooks/useInfiniteScroll.ts +0 -0
  103. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/index.css +0 -0
  104. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/main.tsx +0 -0
  105. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/routes/__root.tsx +0 -0
  106. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/routes/graph.$rootId.tsx +0 -0
  107. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/routes/graphs.tsx +0 -0
  108. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/routes/index.tsx +0 -0
  109. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/routes/registry.tsx +0 -0
  110. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/routes/tasks.$taskId.tsx +0 -0
  111. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/routes/workers.tsx +0 -0
  112. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/utils/format.ts +0 -0
  113. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/src/vite-env.d.ts +0 -0
  114. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tests/fixtures/mock-api.ts +0 -0
  115. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tests/fixtures/mock-data.ts +0 -0
  116. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tests/graphs.spec.ts +0 -0
  117. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tests/registry.spec.ts +0 -0
  118. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tests/task-detail.spec.ts +0 -0
  119. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tests/tasks.spec.ts +0 -0
  120. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tests/workers.spec.ts +0 -0
  121. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tsconfig.json +0 -0
  122. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/tsconfig.tsbuildinfo +0 -0
  123. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/ui/frontend/vite.config.ts +0 -0
  124. {stemtrace-0.2.2 → stemtrace-0.3.1}/src/stemtrace/server/websocket.py +0 -0
  125. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/__init__.py +0 -0
  126. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/conftest.py +0 -0
  127. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/e2e/__init__.py +0 -0
  128. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/e2e/conftest.py +0 -0
  129. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/e2e/test_api_e2e.py +0 -0
  130. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/integration/__init__.py +0 -0
  131. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/integration/test_embedded_static.py +0 -0
  132. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/integration/test_fastapi_integration.py +0 -0
  133. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/integration/test_redis_transport.py +0 -0
  134. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/__init__.py +0 -0
  135. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_auth.py +0 -0
  136. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_bootsteps.py +0 -0
  137. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_config.py +0 -0
  138. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_consumer.py +0 -0
  139. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_events.py +0 -0
  140. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_exceptions.py +0 -0
  141. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_graph.py +0 -0
  142. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_scrubbing.py +0 -0
  143. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_signals.py +0 -0
  144. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_store.py +0 -0
  145. {stemtrace-0.2.2 → stemtrace-0.3.1}/tests/unit/test_websocket.py +0 -0
@@ -1,5 +1,5 @@
1
1
  [tool.bumpversion]
2
- current_version = "0.2.2"
2
+ current_version = "0.3.1"
3
3
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
4
4
  serialize = ["{major}.{minor}.{patch}"]
5
5
  commit = true
@@ -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 docker-compose.e2e.yml build
43
+ docker compose -f "$COMPOSE_FILE" build
26
44
 
27
45
  - name: Start services
28
46
  run: |
29
- docker compose -f docker-compose.e2e.yml up -d
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 docker-compose.e2e.yml logs
72
+ docker compose -f "$COMPOSE_FILE" logs
55
73
 
56
74
  - name: Stop services
57
75
  if: always()
58
- run: docker compose -f docker-compose.e2e.yml down -v
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 docker-compose.e2e.yml build
110
+ docker compose -f "$COMPOSE_FILE" build
74
111
 
75
112
  - name: Start services
76
113
  run: |
77
- docker compose -f docker-compose.e2e.yml up -d
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 docker-compose.e2e.yml logs
188
+ docker compose -f "$COMPOSE_FILE" logs
152
189
 
153
190
  - name: Stop services
154
191
  if: always()
155
- run: docker compose -f docker-compose.e2e.yml down -v
192
+ run: |
193
+ docker compose -f "$COMPOSE_FILE" down -v
@@ -7,8 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.1] - 2026-01-04
11
+
12
+ ### Added
13
+ - UI: optional built-in form login flow for protecting the stemtrace UI
14
+
15
+ ### Changed
16
+ - Config: split server broker URL from worker event transport URL (`broker_url` vs `transport_url`)
17
+ - API: avoid blocking worker/registry refresh operations
18
+ - Docs: clarify optional configuration and retention behavior
19
+
20
+ ### Fixed
21
+ - Workers/Registry: refresh via Celery inspect to reduce stale worker/task registry data
22
+
23
+ ## [0.3.0] - 2026-01-04
24
+
25
+ ### Added
26
+ - RabbitMQ event transport
27
+
28
+ ### Changed
29
+ - Tests: improved RabbitMQ transport coverage and reduced duplication
30
+
31
+ ### Fixed
32
+ - UI: harden derived prefix sanitization
33
+ - CI/E2E: avoid artifact name conflicts
34
+
10
35
  ## [0.2.2] - 2026-01-03
11
36
 
37
+ ### Added
38
+ - README: add release version badge
39
+
40
+ ### Changed
41
+ - Packaging/docs: simplify badges and metadata
42
+ - README: pin PyPI badge to release version
43
+ - Tests: make version assertion dynamic
44
+
45
+ ### Fixed
46
+ - Version bump: sync fix
47
+
12
48
  ## [0.2.1] - 2026-01-03
13
49
 
14
50
  ### Added
@@ -61,7 +97,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
61
97
  - **E2E test suite**: Docker API tests + Playwright browser tests
62
98
  - **Comprehensive test suite**: 350+ Python tests, 90%+ coverage
63
99
 
64
- [unreleased]: https://github.com/iansokolskyi/stemtrace/compare/v0.2.1...HEAD
100
+ [unreleased]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.0...HEAD
101
+ [0.3.0]: https://github.com/iansokolskyi/stemtrace/compare/v0.2.2...v0.3.0
102
+ [0.2.2]: https://github.com/iansokolskyi/stemtrace/compare/v0.2.1...v0.2.2
65
103
  [0.2.1]: https://github.com/iansokolskyi/stemtrace/compare/v0.2.0...v0.2.1
66
104
  [0.2.0]: https://github.com/iansokolskyi/stemtrace/compare/v0.1.1...v0.2.0
67
105
  [0.1.1]: https://github.com/iansokolskyi/stemtrace/compare/v0.1.0...v0.1.1
@@ -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
- @timeout 60 bash -c 'until curl -sf http://localhost:8000/stemtrace/api/health -o /dev/null; do sleep 2; done' || (echo "❌ Service failed to become healthy"; exit 1)
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.2.2
3
+ Version: 0.3.1
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
@@ -56,7 +56,7 @@ Description-Content-Type: text/markdown
56
56
 
57
57
  **Zero-infrastructure Celery task flow visualizer**
58
58
 
59
- [![PyPI version](https://img.shields.io/badge/pypi-v0.2.2-darklime)](https://pypi.org/project/stemtrace)
59
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.3.1-darklime)](https://pypi.org/project/stemtrace)
60
60
  [![Python](https://img.shields.io/pypi/pyversions/stemtrace.svg)](https://pypi.org/project/stemtrace/)
61
61
  [![CI](https://github.com/iansokolskyi/stemtrace/actions/workflows/ci.yml/badge.svg)](https://github.com/iansokolskyi/stemtrace/actions/workflows/ci.yml)
62
62
  [![codecov](https://codecov.io/gh/iansokolskyi/stemtrace/graph/badge.svg)](https://codecov.io/gh/iansokolskyi/stemtrace)
@@ -72,7 +72,7 @@ Ever stared at a failed Celery task wondering "what called this?" or "why did it
72
72
 
73
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.
74
74
 
75
- **Today stemtrace supports Redis** for event transport (via Redis Streams). **RabbitMQ support is planned.**
75
+ **stemtrace supports Redis and RabbitMQ** for event transport.
76
76
 
77
77
  ## ✨ Features
78
78
 
@@ -91,7 +91,7 @@ Stemtrace captures your task executions as a graph — visualize parent→child
91
91
  - **Registry status badges** — Quickly spot tasks that are active, never run, or not registered by any current worker
92
92
 
93
93
  **Production Ready**
94
- - **Zero Infrastructure** — Uses your existing Redis broker, no database needed
94
+ - **Zero Infrastructure** — Uses your existing broker (Redis or RabbitMQ), no database needed
95
95
  - **Sensitive Data Scrubbing** — Passwords and API keys filtered automatically
96
96
  - **Read-Only** — Safe for production; never modifies your task queue
97
97
  - **FastAPI Integration** — Mount into your existing app with one line
@@ -162,6 +162,14 @@ stemtrace server
162
162
 
163
163
  Open [http://localhost:8000](http://localhost:8000).
164
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
+
165
173
  **Option B: Embed in your FastAPI app** (no extra container)
166
174
 
167
175
  ```python
@@ -175,7 +183,7 @@ stemtrace.init_app(app, broker_url="redis://localhost:6379/0")
175
183
 
176
184
  Access at `/stemtrace/` in your existing app — no new services to deploy.
177
185
 
178
- See [Deployment Options](#️-deployment-options) for auth, scaling, and more.
186
+ See [Deployment Options](#deployment-options) for auth, scaling, and more.
179
187
 
180
188
  ## 📦 Architecture
181
189
 
@@ -294,18 +302,58 @@ batch_processor
294
302
  - **Timing** — Each node displays start time and duration directly in the graph
295
303
  - **Aggregate state** — Container shows running/success/failure based on member states
296
304
 
297
- ### Environment Variables
305
+ ### Environment Variables (Optional)
306
+
307
+ You **do not need** these environment variables if you’re using the Python APIs:
308
+ - `stemtrace.init_worker(app, transport_url=..., prefix=..., ttl=...)`
309
+ - `stemtrace.init_app(app, broker_url=..., transport_url=...)`
310
+
311
+ They exist mainly as **convenient defaults** for:
312
+ - `stemtrace server` / `stemtrace consume`
313
+ - container/Docker setups where passing flags is awkward
314
+
315
+ If your app already uses env vars like `BROKER_URL`, `REDIS_URL`, etc., just pass them through:
316
+
317
+ ```python
318
+ import os
319
+ import stemtrace
320
+
321
+ stemtrace.init_app(
322
+ app,
323
+ broker_url=os.environ["BROKER_URL"],
324
+ transport_url=os.getenv("STEMTRACE_TRANSPORT_URL") or os.environ["BROKER_URL"],
325
+ )
326
+ ```
298
327
 
299
328
  | Variable | Description | Default |
300
329
  |----------|-------------|---------|
301
- | `STEMTRACE_BROKER_URL` | Broker URL for `stemtrace server` / `stemtrace consume` and `stemtrace.init_app()` | `redis://localhost:6379/0` |
330
+ | `STEMTRACE_BROKER_URL` | Celery broker URL (used for on-demand worker/registry inspection). Also used as the default for `STEMTRACE_TRANSPORT_URL`. | `redis://localhost:6379/0` |
331
+ | `STEMTRACE_TRANSPORT_URL` | Event transport URL (where stemtrace publishes/consumes events). | Defaults to `STEMTRACE_BROKER_URL`. |
302
332
 
303
333
  ### Supported Brokers
304
334
 
305
335
  | Broker | URL Scheme | Status |
306
336
  |--------|------------|--------|
307
337
  | Redis | `redis://`, `rediss://` | ✅ Supported |
308
- | RabbitMQ | `amqp://`, `amqps://` | 🚧 Planned |
338
+ | RabbitMQ | `amqp://`, `amqps://`, `pyamqp://` | ✅ Supported |
339
+
340
+ ### Event Retention & Server Restarts (Important)
341
+
342
+ stemtrace builds the UI from **events** and keeps state in an **in-memory** graph store.
343
+ That means a `stemtrace server` restart starts from an empty store and only becomes “full”
344
+ again once events are re-consumed.
345
+
346
+ - **Redis (Streams)**: On restart, the server can rebuild state by replaying events that are
347
+ still retained in the stream (bounded by `ttl` / stream trimming).
348
+ - **RabbitMQ (fanout + per-consumer queue)**:
349
+ - Events already consumed/acked by the server are **gone**.
350
+ - Events published while the server is down are only visible after restart if the server’s
351
+ durable per-consumer queue still exists and the messages are still within TTL.
352
+ - **Workers + Registry tabs**: stemtrace uses **Celery inspect** on demand to populate workers
353
+ and registered tasks, so those pages work even if the server missed `worker_ready` events.
354
+ - **If you need durable history across restarts**: point stemtrace events at Redis even if your
355
+ Celery broker is RabbitMQ (set `transport_url` in `stemtrace.init_worker(...)` and set
356
+ `STEMTRACE_TRANSPORT_URL` for the server / embedded setup).
309
357
 
310
358
  ## 🐳 Docker
311
359
 
@@ -315,6 +363,23 @@ docker run -p 8000:8000 \
315
363
  ghcr.io/iansokolskyi/stemtrace
316
364
  ```
317
365
 
366
+ RabbitMQ example:
367
+
368
+ ```bash
369
+ docker run -p 8000:8000 \
370
+ -e STEMTRACE_BROKER_URL=amqp://guest:guest@host.docker.internal:5672// \
371
+ ghcr.io/iansokolskyi/stemtrace
372
+ ```
373
+
374
+ RabbitMQ broker + Redis event transport (recommended if you want history across server restarts):
375
+
376
+ ```bash
377
+ docker run -p 8000:8000 \
378
+ -e STEMTRACE_BROKER_URL=amqp://guest:guest@host.docker.internal:5672// \
379
+ -e STEMTRACE_TRANSPORT_URL=redis://host.docker.internal:6379/0 \
380
+ ghcr.io/iansokolskyi/stemtrace
381
+ ```
382
+
318
383
  Or with Docker Compose:
319
384
 
320
385
  ```yaml
@@ -327,6 +392,8 @@ services:
327
392
  - STEMTRACE_BROKER_URL=redis://redis:6379/0
328
393
  ```
329
394
 
395
+ For a local RabbitMQ setup, see [`docker-compose.rabbitmq.yml`](docker-compose.rabbitmq.yml).
396
+
330
397
  ## 🖥️ Deployment Options
331
398
 
332
399
  `stemtrace` offers two deployment modes depending on your needs:
@@ -353,11 +420,22 @@ Open [http://localhost:8000](http://localhost:8000) to view the dashboard.
353
420
  ```bash
354
421
  stemtrace server \
355
422
  --broker-url redis://myredis:6379/0 \
423
+ --transport-url redis://myredis:6379/0 \
356
424
  --host 0.0.0.0 \
357
425
  --port 8000 \
358
426
  --reload # For development
359
427
  ```
360
428
 
429
+ #### Protecting the Server (Built-in Login Page)
430
+
431
+ ```bash
432
+ stemtrace server \
433
+ --broker-url redis://myredis:6379/0 \
434
+ --login-username admin \
435
+ --login-password secret \
436
+ --login-secret change-me
437
+ ```
438
+
361
439
  #### High-Scale Production Setup
362
440
 
363
441
  Note: `stemtrace server` includes an embedded consumer today (single-process). A multi-process deployment mode is planned.
@@ -379,6 +457,8 @@ That's it. `init_app()` automatically:
379
457
  - Mounts the dashboard at `/stemtrace/`
380
458
  - Starts the event consumer
381
459
 
460
+ Tip: you can also set `transport_url` if you want stemtrace events stored separately from your Celery broker.
461
+
382
462
  #### Configuration Options
383
463
 
384
464
  ```python
@@ -388,6 +468,7 @@ import stemtrace
388
468
  extension = stemtrace.init_app(
389
469
  app,
390
470
  broker_url="redis://localhost:6379/0",
471
+ transport_url=None, # Defaults to broker_url
391
472
  prefix="/stemtrace", # Mount path AND event stream prefix (normalized)
392
473
  ttl=86400, # Event TTL in seconds
393
474
  max_nodes=10000, # Max nodes in memory
@@ -407,7 +488,26 @@ from your_app.auth import require_admin
407
488
  stemtrace.init_app(app, broker_url="redis://localhost:6379/0", auth_dependency=Depends(require_admin))
408
489
  ```
409
490
 
410
- Or use built-in auth helpers:
491
+ #### With Built-in Login Page (Recommended for UI-first)
492
+
493
+ If you primarily use the UI, the easiest way to protect **UI + assets + API + WebSocket**
494
+ is the built-in form login (cookie session):
495
+
496
+ ```python
497
+ import stemtrace
498
+
499
+ stemtrace.init_app(
500
+ app,
501
+ broker_url="redis://localhost:6379/0",
502
+ login_username="admin",
503
+ login_password="secret",
504
+ login_secret="change-me", # recommended for production
505
+ )
506
+ ```
507
+
508
+ This serves a sign-in page at `/stemtrace/login` and protects everything under `/stemtrace`.
509
+
510
+ #### Built-in Auth Helpers (Basic / API key)
411
511
 
412
512
  ```python
413
513
  import stemtrace
@@ -437,12 +537,12 @@ stemtrace.init_app(
437
537
  - ✅ **Sensitive data scrubbing** — Passwords and API keys filtered automatically
438
538
  - ✅ **Real-time updates** — WebSocket-powered live dashboard
439
539
  - ✅ **FastAPI integration** — Mount into your existing app
540
+ - ✅ **RabbitMQ support** — Use your existing RabbitMQ broker (`amqp://`, `amqps://`, `pyamqp://`)
440
541
  - ✅ **Workers page** — Monitor online/offline workers and their registered tasks
441
542
  - ✅ **Task registry** — Browse discovered + registered tasks with clear status badges
442
543
 
443
544
  ### Coming Soon
444
545
 
445
- - 🔜 **RabbitMQ support** — Use your existing RabbitMQ broker
446
546
  - 🔜 **Anomaly detection** — Spot stuck, orphaned, or failed tasks
447
547
  - 🔜 **Dashboard with stats** — Success rates, durations, failure trends
448
548
  - 🔜 **OpenTelemetry export** — Send traces to Jaeger, Tempo, Datadog