flowsense-engine 0.2.1__tar.gz → 0.4.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.
- flowsense_engine-0.4.0/CHANGELOG.md +107 -0
- flowsense_engine-0.4.0/MANIFEST.in +2 -0
- {flowsense_engine-0.2.1/src/flowsense_engine.egg-info → flowsense_engine-0.4.0}/PKG-INFO +61 -11
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/README.md +60 -10
- flowsense_engine-0.4.0/docs/alerting.md +57 -0
- flowsense_engine-0.4.0/docs/architecture.md +138 -0
- flowsense_engine-0.4.0/docs/authentication.md +77 -0
- flowsense_engine-0.4.0/docs/benchmarks.md +37 -0
- flowsense_engine-0.4.0/docs/grafana.md +66 -0
- flowsense_engine-0.4.0/docs/migrating-to-0.3.md +66 -0
- flowsense_engine-0.4.0/docs/prometheus.md +58 -0
- flowsense_engine-0.4.0/docs/python-api.md +142 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/docs/releasing.md +6 -2
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/pyproject.toml +4 -3
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/__init__.py +26 -0
- flowsense_engine-0.4.0/src/flowsense/application/__init__.py +52 -0
- flowsense_engine-0.4.0/src/flowsense/application/analysis_engine.py +71 -0
- flowsense_engine-0.4.0/src/flowsense/application/analyzer.py +21 -0
- flowsense_engine-0.4.0/src/flowsense/application/batch.py +129 -0
- flowsense_engine-0.4.0/src/flowsense/application/client.py +61 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/application/output.py +17 -0
- flowsense_engine-0.4.0/src/flowsense/application/ports.py +43 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/application/serialization.py +35 -0
- flowsense_engine-0.4.0/src/flowsense/application/use_cases.py +36 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/cli/main.py +41 -11
- flowsense_engine-0.4.0/src/flowsense/collector/__init__.py +9 -0
- flowsense_engine-0.4.0/src/flowsense/config.py +22 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/domain/__init__.py +2 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/domain/exceptions.py +6 -0
- flowsense_engine-0.4.0/src/flowsense/domain/models.py +28 -0
- flowsense_engine-0.4.0/src/flowsense/engine/analyzer.py +23 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/change_point.py +3 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/drift.py +3 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/root_cause.py +3 -1
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/trend.py +3 -0
- flowsense_engine-0.4.0/src/flowsense/engine/validation.py +12 -0
- flowsense_engine-0.4.0/src/flowsense/infrastructure/airflow/__init__.py +34 -0
- flowsense_engine-0.4.0/src/flowsense/infrastructure/airflow/auth.py +63 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/infrastructure/airflow/client.py +64 -50
- {flowsense_engine-0.2.1/src/flowsense → flowsense_engine-0.4.0/src/flowsense/infrastructure/airflow}/config.py +26 -9
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/infrastructure/airflow/dto.py +9 -1
- flowsense_engine-0.4.0/src/flowsense/infrastructure/airflow/factory.py +35 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/mcp/server.py +3 -11
- flowsense_engine-0.4.0/src/flowsense/models/__init__.py +17 -0
- flowsense_engine-0.4.0/src/flowsense/observability/__init__.py +5 -0
- flowsense_engine-0.4.0/src/flowsense/observability/prometheus.py +248 -0
- flowsense_engine-0.4.0/src/flowsense/observability/service.py +90 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0/src/flowsense_engine.egg-info}/PKG-INFO +61 -11
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense_engine.egg-info/SOURCES.txt +32 -0
- flowsense_engine-0.4.0/tests/test_airflow_auth.py +114 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_airflow_client.py +22 -31
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_airflow_client_integration.py +2 -2
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_airflow_compatibility.py +86 -11
- flowsense_engine-0.4.0/tests/test_airflow_contract.py +95 -0
- flowsense_engine-0.4.0/tests/test_airflow_factory.py +76 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_airflow_resilience.py +7 -8
- flowsense_engine-0.4.0/tests/test_analysis_golden.py +111 -0
- flowsense_engine-0.4.0/tests/test_analysis_use_case.py +68 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_analyzer.py +1 -2
- flowsense_engine-0.4.0/tests/test_architecture.py +78 -0
- flowsense_engine-0.4.0/tests/test_batch_analysis_output.py +71 -0
- flowsense_engine-0.4.0/tests/test_benchmark_analysis.py +56 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_cli.py +69 -31
- flowsense_engine-0.4.0/tests/test_deprecations.py +26 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_domain.py +39 -9
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_history.py +1 -1
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_impact.py +1 -1
- flowsense_engine-0.4.0/tests/test_library_client.py +169 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_mcp_server.py +15 -13
- flowsense_engine-0.4.0/tests/test_observability_assets.py +58 -0
- flowsense_engine-0.4.0/tests/test_observation_validation.py +27 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_package_metadata.py +1 -1
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_policy.py +1 -2
- flowsense_engine-0.4.0/tests/test_prometheus.py +152 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_propagation.py +1 -1
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_public_api.py +36 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_root_cause.py +22 -3
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_timing.py +1 -2
- flowsense_engine-0.2.1/CHANGELOG.md +0 -48
- flowsense_engine-0.2.1/MANIFEST.in +0 -2
- flowsense_engine-0.2.1/src/flowsense/application/__init__.py +0 -20
- flowsense_engine-0.2.1/src/flowsense/application/analyzer.py +0 -68
- flowsense_engine-0.2.1/src/flowsense/application/ports.py +0 -11
- flowsense_engine-0.2.1/src/flowsense/domain/models.py +0 -19
- flowsense_engine-0.2.1/src/flowsense/engine/analyzer.py +0 -17
- flowsense_engine-0.2.1/src/flowsense/infrastructure/airflow/__init__.py +0 -13
- flowsense_engine-0.2.1/src/flowsense/mcp/__init__.py +0 -0
- flowsense_engine-0.2.1/src/flowsense/models/__init__.py +0 -7
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/LICENSE +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/setup.cfg +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/application/pipeline.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/application/request.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/cli/__init__.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/cli/report.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/collector/airflow_client.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/domain/enums.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/domain/policy.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/domain/results.py +0 -0
- {flowsense_engine-0.2.1/src/flowsense/collector → flowsense_engine-0.4.0/src/flowsense/engine}/__init__.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/history.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/impact.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/propagation.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/engine/timing.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/infrastructure/__init__.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/infrastructure/airflow/exceptions.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/infrastructure/airflow/mapper.py +0 -0
- {flowsense_engine-0.2.1/src/flowsense/engine → flowsense_engine-0.4.0/src/flowsense/mcp}/__init__.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/models/dag_analysis.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/models/task_run.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/py.typed +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense/version.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense_engine.egg-info/dependency_links.txt +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense_engine.egg-info/entry_points.txt +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense_engine.egg-info/requires.txt +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/src/flowsense_engine.egg-info/top_level.txt +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_airflow_mapper.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_analysis_output.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_analysis_pipeline.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_analysis_request.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_change_point.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_cli_report.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_dag_summary.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_drift.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_mcp_integration.py +0 -0
- {flowsense_engine-0.2.1 → flowsense_engine-0.4.0}/tests/test_trend.py +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to FlowSense are documented in this file. The project uses
|
|
4
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.4.0] - 2026-09-20
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added paginated Airflow 2 and 3 DAG discovery with optional paused-DAG
|
|
13
|
+
inclusion.
|
|
14
|
+
- Added an immutable multi-DAG analysis result and bounded, opt-in concurrency
|
|
15
|
+
through `FlowSenseClient.analyze_many()`.
|
|
16
|
+
- Added a versioned, typed batch output document with serialization and JSON
|
|
17
|
+
Schema helpers.
|
|
18
|
+
- Added the `FlowSenseClient` facade for concise embedded Python usage and an
|
|
19
|
+
explicit Airflow data-source factory for application-owned configuration.
|
|
20
|
+
- Added pluggable Airflow authentication providers for Basic Auth, login-token
|
|
21
|
+
exchange, static or rotating bearer tokens, and deployment-specific headers.
|
|
22
|
+
- Added a bounded Prometheus metrics exporter and the optional
|
|
23
|
+
`flowsense serve-metrics` command for continuous DAG analysis.
|
|
24
|
+
- Added a provisioned Grafana dashboard and local Docker Compose example for
|
|
25
|
+
inspecting analysis health, coverage, severity, task drift, and handoffs.
|
|
26
|
+
- Added Prometheus alert rules, Alertmanager configuration, synthetic rule
|
|
27
|
+
tests, and CI validation for FlowSense analysis failures and anomalies.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Kept observability integrations as optional delivery adapters so the core
|
|
32
|
+
analysis package remains independent from Prometheus, Grafana, and hosted
|
|
33
|
+
service infrastructure.
|
|
34
|
+
|
|
35
|
+
## [0.3.0] - 2026-09-20
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- Added `AnalyzeDAG` as the shared application use-case boundary for CLI, MCP,
|
|
40
|
+
and library integrations.
|
|
41
|
+
- Added the `DAGAnalysisEngine` extension port and injectable default analysis
|
|
42
|
+
engine.
|
|
43
|
+
- Added versioned golden regression coverage for the complete analysis output.
|
|
44
|
+
- Added deterministic performance benchmarks with machine-readable results and
|
|
45
|
+
a manually triggered GitHub Actions workflow.
|
|
46
|
+
- Added an Airflow 2 and Airflow 3 REST contract test matrix covering
|
|
47
|
+
authentication, routing, validation, mapping, and end-to-end analysis.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- Separated environment loading and Airflow client construction through explicit
|
|
52
|
+
`AirflowConfig` and infrastructure factories.
|
|
53
|
+
- Made the `TaskRun` domain entity immutable and framework-independent while
|
|
54
|
+
keeping Pydantic at external DTO and output-contract boundaries.
|
|
55
|
+
- Added automated enforcement preventing the domain layer from importing
|
|
56
|
+
Pydantic.
|
|
57
|
+
- Added architecture dependency guardrails and documented supported extension
|
|
58
|
+
points and compatibility boundaries.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- Rejected non-finite and negative analysis inputs at the domain boundary.
|
|
63
|
+
- Made root-cause selection deterministic when candidates have equal scores.
|
|
64
|
+
|
|
65
|
+
## [0.2.1] - 2026-09-10
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- Renamed the Python distribution to `flowsense-engine` while preserving the
|
|
70
|
+
`flowsense` import package and CLI command.
|
|
71
|
+
- Added tokenless PyPI publishing through GitHub Actions Trusted Publishing.
|
|
72
|
+
|
|
73
|
+
## [0.2.0] - 2026-09-10
|
|
74
|
+
|
|
75
|
+
### Added
|
|
76
|
+
|
|
77
|
+
- Task handoff drift, impact classification, propagation, and root-cause analysis.
|
|
78
|
+
- Configurable drift, mapped-task aggregation, change-point, and trend policies.
|
|
79
|
+
- Apache Airflow 2 and 3 API compatibility with pagination and bounded history.
|
|
80
|
+
- Retry, timeout, backoff, and `Retry-After` handling for Airflow requests.
|
|
81
|
+
- Historical DAG run analysis with preceding-history isolation.
|
|
82
|
+
- Rich CLI reports, JSON output, severity-based exit thresholds, and schema output.
|
|
83
|
+
- MCP analysis tool with the same policy and versioned response contract as the CLI.
|
|
84
|
+
- Typed `AnalysisRequest` and `AnalysisDocument` contracts with JSON Schema support.
|
|
85
|
+
- Supported top-level library API, typed package marker, and Python 3.12/3.13 CI.
|
|
86
|
+
|
|
87
|
+
### Changed
|
|
88
|
+
|
|
89
|
+
- Split the analysis workflow into domain, application, infrastructure, and adapter
|
|
90
|
+
boundaries.
|
|
91
|
+
- Analysis output schema advanced to version `1.1` with `current_dag_run_id`.
|
|
92
|
+
- Expected configuration, Airflow API, and payload failures now use a unified error
|
|
93
|
+
hierarchy.
|
|
94
|
+
|
|
95
|
+
### Fixed
|
|
96
|
+
|
|
97
|
+
- Preserved anomaly origins across normal dependency gaps.
|
|
98
|
+
- Detected drift when the historical median absolute deviation is zero.
|
|
99
|
+
- Aggregated dynamically mapped task instances before analysis.
|
|
100
|
+
- Reported insufficient history and invalid handoff timing as diagnostics.
|
|
101
|
+
|
|
102
|
+
## [0.1.0] - 2026-08-18
|
|
103
|
+
|
|
104
|
+
### Added
|
|
105
|
+
|
|
106
|
+
- Initial FlowSense prototype with Airflow task-duration collection and robust
|
|
107
|
+
median/MAD drift detection.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowsense-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Temporal drift and anomaly detection for Apache Airflow
|
|
5
5
|
Author: Omer Cengiz
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -37,8 +37,11 @@ Dynamic: license-file
|
|
|
37
37
|
|
|
38
38
|
Temporal drift, anomaly detection, and dependency-aware propagation analysis for Apache Airflow.
|
|
39
39
|
|
|
40
|
-
Current package release: `0.
|
|
41
|
-
notes
|
|
40
|
+
Current package release: `0.4.0`. See [CHANGELOG.md](CHANGELOG.md) for release
|
|
41
|
+
notes, [docs/architecture.md](docs/architecture.md) for the system architecture,
|
|
42
|
+
[docs/benchmarks.md](docs/benchmarks.md) for performance measurement, and
|
|
43
|
+
[docs/migrating-to-0.3.md](docs/migrating-to-0.3.md) for migration guidance.
|
|
44
|
+
Maintainers can use [docs/releasing.md](docs/releasing.md) as the release checklist.
|
|
42
45
|
|
|
43
46
|
FlowSense analyzes historical DAG executions to identify abnormal task behavior and trace how anomalies propagate through downstream dependencies.
|
|
44
47
|
|
|
@@ -177,6 +180,7 @@ AIRFLOW_USERNAME=your_username
|
|
|
177
180
|
AIRFLOW_PASSWORD=your_password
|
|
178
181
|
AIRFLOW_API_VERSION=v2
|
|
179
182
|
AIRFLOW_AUTH_MODE=token
|
|
183
|
+
# AIRFLOW_BEARER_TOKEN=your_static_token
|
|
180
184
|
AIRFLOW_CONNECT_TIMEOUT=10
|
|
181
185
|
AIRFLOW_READ_TIMEOUT=10
|
|
182
186
|
AIRFLOW_MAX_RETRIES=2
|
|
@@ -189,6 +193,16 @@ Stable REST API deployments. Airflow 3.x uses the `v2` API and typically uses
|
|
|
189
193
|
token authentication. Authentication still depends on the API auth backend
|
|
190
194
|
configured in the Airflow deployment.
|
|
191
195
|
|
|
196
|
+
Static bearer tokens can use `AIRFLOW_AUTH_MODE=bearer` with
|
|
197
|
+
`AIRFLOW_BEARER_TOKEN`; username and password are not required in that mode.
|
|
198
|
+
Library integrations may inject a custom `AirflowAuthProvider` for rotating
|
|
199
|
+
tokens, identity-aware proxies, or deployment-specific headers. See
|
|
200
|
+
[docs/authentication.md](docs/authentication.md) for the complete contract.
|
|
201
|
+
|
|
202
|
+
CI verifies both integrations through versioned Airflow 2 and Airflow 3 REST
|
|
203
|
+
contract fixtures. These boundary tests cover authentication, endpoint routing,
|
|
204
|
+
response validation, domain mapping, and the complete analysis use case.
|
|
205
|
+
|
|
192
206
|
Transient transport failures and HTTP `429`, `502`, `503`, and `504` responses
|
|
193
207
|
are retried with exponential backoff. `Retry-After` is honored when Airflow
|
|
194
208
|
provides it. Connect/read timeouts, retry count, and base backoff can be tuned
|
|
@@ -272,22 +286,41 @@ tooling, or client code generation.
|
|
|
272
286
|
|
|
273
287
|
## Library API
|
|
274
288
|
|
|
275
|
-
|
|
276
|
-
|
|
289
|
+
`FlowSenseClient` is the recommended in-process Python API. The environment
|
|
290
|
+
configured Airflow factory keeps the basic setup concise:
|
|
277
291
|
|
|
278
292
|
```python
|
|
279
|
-
from flowsense import
|
|
293
|
+
from flowsense import FlowSenseClient
|
|
294
|
+
from flowsense.infrastructure.airflow import create_airflow_data_source
|
|
280
295
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
dag_id="flowsense_demo",
|
|
284
|
-
source=source,
|
|
285
|
-
)
|
|
296
|
+
client = FlowSenseClient(create_airflow_data_source)
|
|
297
|
+
analysis = client.analyze("flowsense_demo")
|
|
286
298
|
|
|
287
299
|
print(analysis.overall_severity)
|
|
288
300
|
print(analysis.primary_origin)
|
|
289
301
|
```
|
|
290
302
|
|
|
303
|
+
Applications that own configuration can combine `AirflowConfig` with
|
|
304
|
+
`create_airflow_data_source_factory`. Typed integrations may continue to call
|
|
305
|
+
`client.execute(AnalysisRequest(...))`. See the complete
|
|
306
|
+
[Python API guide](docs/python-api.md).
|
|
307
|
+
|
|
308
|
+
Multiple DAGs can be analyzed with bounded, opt-in concurrency. Expected
|
|
309
|
+
FlowSense failures are isolated per DAG:
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
result = client.analyze_many(
|
|
313
|
+
["orders", "payments", "inventory"],
|
|
314
|
+
max_concurrency=3,
|
|
315
|
+
)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
`AirflowClient.list_dag_ids()` provides paginated DAG discovery and excludes
|
|
319
|
+
paused DAGs by default.
|
|
320
|
+
|
|
321
|
+
`serialize_batch_analysis(result)` converts the result into the stable batch
|
|
322
|
+
output contract without exposing raw exception objects.
|
|
323
|
+
|
|
291
324
|
Analysis behavior can be customized with an immutable policy:
|
|
292
325
|
|
|
293
326
|
```python
|
|
@@ -345,6 +378,23 @@ The server exposes the `analyze_airflow_dag` tool, which returns task drift,
|
|
|
345
378
|
handoff drift, impact classification, propagation paths, and primary root-cause
|
|
346
379
|
information for a DAG.
|
|
347
380
|
|
|
381
|
+
## Prometheus
|
|
382
|
+
|
|
383
|
+
Run continuous analysis and expose the latest DAG and bounded task-level metrics:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
flowsense serve-metrics example_dag --host 0.0.0.0 --port 9108
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
See [docs/prometheus.md](docs/prometheus.md) for the metric contract,
|
|
390
|
+
cardinality policy, and Prometheus scrape configuration.
|
|
391
|
+
|
|
392
|
+
A provisioned Prometheus and Grafana development stack, including the
|
|
393
|
+
`FlowSense Overview` dashboard, is documented in
|
|
394
|
+
[docs/grafana.md](docs/grafana.md).
|
|
395
|
+
Default operational alerts and Alertmanager routing are documented in
|
|
396
|
+
[docs/alerting.md](docs/alerting.md).
|
|
397
|
+
|
|
348
398
|
## Development
|
|
349
399
|
|
|
350
400
|
Run unit tests:
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Temporal drift, anomaly detection, and dependency-aware propagation analysis for Apache Airflow.
|
|
4
4
|
|
|
5
|
-
Current package release: `0.
|
|
6
|
-
notes
|
|
5
|
+
Current package release: `0.4.0`. See [CHANGELOG.md](CHANGELOG.md) for release
|
|
6
|
+
notes, [docs/architecture.md](docs/architecture.md) for the system architecture,
|
|
7
|
+
[docs/benchmarks.md](docs/benchmarks.md) for performance measurement, and
|
|
8
|
+
[docs/migrating-to-0.3.md](docs/migrating-to-0.3.md) for migration guidance.
|
|
9
|
+
Maintainers can use [docs/releasing.md](docs/releasing.md) as the release checklist.
|
|
7
10
|
|
|
8
11
|
FlowSense analyzes historical DAG executions to identify abnormal task behavior and trace how anomalies propagate through downstream dependencies.
|
|
9
12
|
|
|
@@ -142,6 +145,7 @@ AIRFLOW_USERNAME=your_username
|
|
|
142
145
|
AIRFLOW_PASSWORD=your_password
|
|
143
146
|
AIRFLOW_API_VERSION=v2
|
|
144
147
|
AIRFLOW_AUTH_MODE=token
|
|
148
|
+
# AIRFLOW_BEARER_TOKEN=your_static_token
|
|
145
149
|
AIRFLOW_CONNECT_TIMEOUT=10
|
|
146
150
|
AIRFLOW_READ_TIMEOUT=10
|
|
147
151
|
AIRFLOW_MAX_RETRIES=2
|
|
@@ -154,6 +158,16 @@ Stable REST API deployments. Airflow 3.x uses the `v2` API and typically uses
|
|
|
154
158
|
token authentication. Authentication still depends on the API auth backend
|
|
155
159
|
configured in the Airflow deployment.
|
|
156
160
|
|
|
161
|
+
Static bearer tokens can use `AIRFLOW_AUTH_MODE=bearer` with
|
|
162
|
+
`AIRFLOW_BEARER_TOKEN`; username and password are not required in that mode.
|
|
163
|
+
Library integrations may inject a custom `AirflowAuthProvider` for rotating
|
|
164
|
+
tokens, identity-aware proxies, or deployment-specific headers. See
|
|
165
|
+
[docs/authentication.md](docs/authentication.md) for the complete contract.
|
|
166
|
+
|
|
167
|
+
CI verifies both integrations through versioned Airflow 2 and Airflow 3 REST
|
|
168
|
+
contract fixtures. These boundary tests cover authentication, endpoint routing,
|
|
169
|
+
response validation, domain mapping, and the complete analysis use case.
|
|
170
|
+
|
|
157
171
|
Transient transport failures and HTTP `429`, `502`, `503`, and `504` responses
|
|
158
172
|
are retried with exponential backoff. `Retry-After` is honored when Airflow
|
|
159
173
|
provides it. Connect/read timeouts, retry count, and base backoff can be tuned
|
|
@@ -237,22 +251,41 @@ tooling, or client code generation.
|
|
|
237
251
|
|
|
238
252
|
## Library API
|
|
239
253
|
|
|
240
|
-
|
|
241
|
-
|
|
254
|
+
`FlowSenseClient` is the recommended in-process Python API. The environment
|
|
255
|
+
configured Airflow factory keeps the basic setup concise:
|
|
242
256
|
|
|
243
257
|
```python
|
|
244
|
-
from flowsense import
|
|
258
|
+
from flowsense import FlowSenseClient
|
|
259
|
+
from flowsense.infrastructure.airflow import create_airflow_data_source
|
|
245
260
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
dag_id="flowsense_demo",
|
|
249
|
-
source=source,
|
|
250
|
-
)
|
|
261
|
+
client = FlowSenseClient(create_airflow_data_source)
|
|
262
|
+
analysis = client.analyze("flowsense_demo")
|
|
251
263
|
|
|
252
264
|
print(analysis.overall_severity)
|
|
253
265
|
print(analysis.primary_origin)
|
|
254
266
|
```
|
|
255
267
|
|
|
268
|
+
Applications that own configuration can combine `AirflowConfig` with
|
|
269
|
+
`create_airflow_data_source_factory`. Typed integrations may continue to call
|
|
270
|
+
`client.execute(AnalysisRequest(...))`. See the complete
|
|
271
|
+
[Python API guide](docs/python-api.md).
|
|
272
|
+
|
|
273
|
+
Multiple DAGs can be analyzed with bounded, opt-in concurrency. Expected
|
|
274
|
+
FlowSense failures are isolated per DAG:
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
result = client.analyze_many(
|
|
278
|
+
["orders", "payments", "inventory"],
|
|
279
|
+
max_concurrency=3,
|
|
280
|
+
)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
`AirflowClient.list_dag_ids()` provides paginated DAG discovery and excludes
|
|
284
|
+
paused DAGs by default.
|
|
285
|
+
|
|
286
|
+
`serialize_batch_analysis(result)` converts the result into the stable batch
|
|
287
|
+
output contract without exposing raw exception objects.
|
|
288
|
+
|
|
256
289
|
Analysis behavior can be customized with an immutable policy:
|
|
257
290
|
|
|
258
291
|
```python
|
|
@@ -310,6 +343,23 @@ The server exposes the `analyze_airflow_dag` tool, which returns task drift,
|
|
|
310
343
|
handoff drift, impact classification, propagation paths, and primary root-cause
|
|
311
344
|
information for a DAG.
|
|
312
345
|
|
|
346
|
+
## Prometheus
|
|
347
|
+
|
|
348
|
+
Run continuous analysis and expose the latest DAG and bounded task-level metrics:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
flowsense serve-metrics example_dag --host 0.0.0.0 --port 9108
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
See [docs/prometheus.md](docs/prometheus.md) for the metric contract,
|
|
355
|
+
cardinality policy, and Prometheus scrape configuration.
|
|
356
|
+
|
|
357
|
+
A provisioned Prometheus and Grafana development stack, including the
|
|
358
|
+
`FlowSense Overview` dashboard, is documented in
|
|
359
|
+
[docs/grafana.md](docs/grafana.md).
|
|
360
|
+
Default operational alerts and Alertmanager routing are documented in
|
|
361
|
+
[docs/alerting.md](docs/alerting.md).
|
|
362
|
+
|
|
313
363
|
## Development
|
|
314
364
|
|
|
315
365
|
Run unit tests:
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Prometheus alerting
|
|
2
|
+
|
|
3
|
+
The local observability stack loads a tested set of FlowSense alert rules and
|
|
4
|
+
routes firing alerts to Alertmanager.
|
|
5
|
+
|
|
6
|
+
## Included alerts
|
|
7
|
+
|
|
8
|
+
| Alert | Default condition | Severity |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| `FlowSenseExporterDown` | Metrics endpoint unavailable for 2 minutes | Critical |
|
|
11
|
+
| `FlowSenseAnalysisFailed` | Latest analysis failed for 2 minutes | Warning |
|
|
12
|
+
| `FlowSenseAnalysisStale` | No successful analysis for 10 minutes in total | Warning |
|
|
13
|
+
| `FlowSenseCriticalDAG` | DAG severity remains critical for 2 minutes | Critical |
|
|
14
|
+
| `FlowSenseCriticalTask` | Task severity remains critical for 2 minutes | Critical |
|
|
15
|
+
| `FlowSenseTaskMetricsDropped` | Cardinality limit omits tasks for 5 minutes | Warning |
|
|
16
|
+
| `FlowSenseAnalysisSlow` | Analysis remains above 30 seconds for 5 minutes | Warning |
|
|
17
|
+
|
|
18
|
+
The stale rule expression becomes true after five minutes without a successful
|
|
19
|
+
analysis and must remain true for another five minutes before firing. Adjust
|
|
20
|
+
thresholds in `deploy/observability/alerts.yml` to match the configured analysis
|
|
21
|
+
interval and operational expectations.
|
|
22
|
+
|
|
23
|
+
## Validate rules
|
|
24
|
+
|
|
25
|
+
Run syntax and unit checks with the Prometheus image pinned by the Compose file:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
docker run --rm \
|
|
29
|
+
--entrypoint promtool \
|
|
30
|
+
-v "$PWD/deploy/observability:/workspace:ro" \
|
|
31
|
+
-w /workspace \
|
|
32
|
+
prom/prometheus:v3.14.0 \
|
|
33
|
+
check rules alerts.yml
|
|
34
|
+
|
|
35
|
+
docker run --rm \
|
|
36
|
+
--entrypoint promtool \
|
|
37
|
+
-v "$PWD/deploy/observability:/workspace:ro" \
|
|
38
|
+
-w /workspace \
|
|
39
|
+
prom/prometheus:v3.14.0 \
|
|
40
|
+
test rules alerts.test.yml
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Configure notifications
|
|
44
|
+
|
|
45
|
+
The committed Alertmanager configuration intentionally uses an empty local
|
|
46
|
+
receiver. Firing alerts are visible in the Alertmanager UI and the Grafana
|
|
47
|
+
dashboard, but no external notification is sent by default.
|
|
48
|
+
|
|
49
|
+
For production, replace the receiver in
|
|
50
|
+
`deploy/observability/alertmanager.yml` with the organization's managed email,
|
|
51
|
+
Slack, PagerDuty, webhook, or other supported integration. Keep credentials out
|
|
52
|
+
of Git and inject them through the deployment platform's secret management
|
|
53
|
+
mechanism.
|
|
54
|
+
|
|
55
|
+
Alertmanager is available locally at `http://localhost:9093`. Verify routing and
|
|
56
|
+
notification delivery in a non-production environment before enabling it for
|
|
57
|
+
operational incidents.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# FlowSense Architecture
|
|
2
|
+
|
|
3
|
+
FlowSense uses an inward-facing layered architecture. Delivery mechanisms and
|
|
4
|
+
external systems depend on application contracts; the analysis domain does not
|
|
5
|
+
depend on Airflow, CLI, MCP, or environment configuration.
|
|
6
|
+
|
|
7
|
+
## Dependency direction
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
CLI / MCP
|
|
11
|
+
|
|
|
12
|
+
v
|
|
13
|
+
Application use cases -----> Domain models and policies
|
|
14
|
+
| ^
|
|
15
|
+
v |
|
|
16
|
+
Application ports <----- Infrastructure adapters
|
|
17
|
+
|
|
|
18
|
+
v
|
|
19
|
+
Apache Airflow
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Dependencies must point toward the application and domain layers. The
|
|
23
|
+
composition roots in the CLI and MCP adapters are responsible for selecting
|
|
24
|
+
concrete infrastructure implementations.
|
|
25
|
+
|
|
26
|
+
## Layers
|
|
27
|
+
|
|
28
|
+
### Domain
|
|
29
|
+
|
|
30
|
+
`flowsense.domain` contains the analysis vocabulary: task runs, policies,
|
|
31
|
+
severity and impact classifications, results, and expected domain failures.
|
|
32
|
+
It must not import application, infrastructure, CLI, MCP, or compatibility
|
|
33
|
+
modules. Domain entities and results use standard-library dataclasses; they do
|
|
34
|
+
not depend on validation or transport frameworks.
|
|
35
|
+
|
|
36
|
+
`flowsense.engine` currently contains pure analysis services such as drift,
|
|
37
|
+
trend, handoff, propagation, and root-cause calculations. These services may
|
|
38
|
+
depend on the domain but not on delivery or infrastructure code.
|
|
39
|
+
|
|
40
|
+
### Application
|
|
41
|
+
|
|
42
|
+
`flowsense.application` coordinates use cases without knowing how Airflow data
|
|
43
|
+
is retrieved or how results are displayed.
|
|
44
|
+
|
|
45
|
+
`AnalysisRequest` is the validated input contract. `AnalyzeDAG.execute()` is the
|
|
46
|
+
primary use-case boundary. `DAGDataSource` and `DAGDataSourceFactory` are ports
|
|
47
|
+
implemented by infrastructure adapters. The existing functional
|
|
48
|
+
`analyze_dag(dag_id, source, policy)` API remains available for callers that
|
|
49
|
+
already own a data source.
|
|
50
|
+
|
|
51
|
+
`FlowSenseClient` is the supported convenience facade for embedded Python
|
|
52
|
+
consumers. It translates the concise `analyze(...)` call into an
|
|
53
|
+
`AnalysisRequest` and delegates to `AnalyzeDAG`; it contains no collection or
|
|
54
|
+
analysis logic of its own. Its optional multi-DAG operation creates one
|
|
55
|
+
use-case execution and context-managed data source per DAG, preserving the
|
|
56
|
+
single-DAG application boundary.
|
|
57
|
+
|
|
58
|
+
`BatchAnalysisDocument` is a separate versioned envelope around the existing
|
|
59
|
+
single-DAG `AnalysisDocument`. Expected failures cross the output boundary as
|
|
60
|
+
typed failure records rather than runtime exception objects.
|
|
61
|
+
|
|
62
|
+
`DAGAnalysisEngine` is the coarse-grained algorithm extension port. The default
|
|
63
|
+
implementation owns the complete statistical workflow after data collection.
|
|
64
|
+
Alternative engines can be injected into `AnalyzeDAG` without changing CLI,
|
|
65
|
+
MCP, data-source, or output-contract code. Individual detector interfaces are
|
|
66
|
+
intentionally avoided until independent detector replacement is required.
|
|
67
|
+
|
|
68
|
+
### Infrastructure
|
|
69
|
+
|
|
70
|
+
`flowsense.infrastructure.airflow` implements Airflow HTTP access. Pydantic DTOs
|
|
71
|
+
validate external API payloads and mappers translate them into domain objects.
|
|
72
|
+
Pydantic is intentionally restricted to infrastructure DTOs and application
|
|
73
|
+
output contracts, where runtime boundary validation and JSON Schema generation
|
|
74
|
+
are required.
|
|
75
|
+
|
|
76
|
+
`AirflowClient` receives an explicit `AirflowConfig` and never reads environment
|
|
77
|
+
variables. `load_airflow_config()` and `create_airflow_data_source()` belong to
|
|
78
|
+
the infrastructure composition boundary.
|
|
79
|
+
|
|
80
|
+
Authentication is supplied through `AirflowAuthProvider`. Built-in providers
|
|
81
|
+
cover Basic Auth, Airflow login-token exchange, static bearer tokens, and custom
|
|
82
|
+
headers without coupling request collection to a deployment's identity system.
|
|
83
|
+
|
|
84
|
+
### Delivery adapters
|
|
85
|
+
|
|
86
|
+
`flowsense.cli`, `flowsense.mcp`, and `flowsense.observability` translate user input into an
|
|
87
|
+
`AnalysisRequest`, invoke `AnalyzeDAG`, and translate the result into their own
|
|
88
|
+
output mechanism. Prometheus export implements the `AnalysisMetricsSink` port
|
|
89
|
+
and keeps a bounded latest-value snapshot. Business analysis and data-collection
|
|
90
|
+
orchestration must not be duplicated in these adapters.
|
|
91
|
+
|
|
92
|
+
## Main analysis flow
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
Input options
|
|
96
|
+
-> AnalysisRequest
|
|
97
|
+
-> AnalyzeDAG
|
|
98
|
+
-> DAGDataSourceFactory
|
|
99
|
+
-> DAGDataSource
|
|
100
|
+
-> task and handoff histories
|
|
101
|
+
-> drift / change-point / trend analysis
|
|
102
|
+
-> impact and propagation analysis
|
|
103
|
+
-> primary root-cause selection
|
|
104
|
+
-> DAGAnalysis
|
|
105
|
+
-> versioned AnalysisDocument
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Extension points
|
|
109
|
+
|
|
110
|
+
- Add another data source by implementing `DAGDataSource` and providing a
|
|
111
|
+
`DAGDataSourceFactory`.
|
|
112
|
+
- Replace the complete analysis workflow by implementing `DAGAnalysisEngine`
|
|
113
|
+
and injecting it into `AnalyzeDAG`.
|
|
114
|
+
- Add a delivery mechanism by creating an adapter that builds an
|
|
115
|
+
`AnalysisRequest` and invokes `AnalyzeDAG`.
|
|
116
|
+
- Extend output consumers through `AnalysisDocument`; incompatible contract
|
|
117
|
+
changes require a schema-version change.
|
|
118
|
+
- Keep external payload models inside their infrastructure adapter and map them
|
|
119
|
+
into domain models before analysis.
|
|
120
|
+
|
|
121
|
+
## Compatibility policy
|
|
122
|
+
|
|
123
|
+
The following pre-layered import paths remain temporarily available:
|
|
124
|
+
|
|
125
|
+
- `flowsense.models` -> `flowsense.domain`
|
|
126
|
+
- `flowsense.collector` -> `flowsense.infrastructure.airflow`
|
|
127
|
+
- `flowsense.config` -> `flowsense.infrastructure.airflow`
|
|
128
|
+
- `flowsense.engine.analyzer` -> `flowsense.AnalyzeDAG`
|
|
129
|
+
|
|
130
|
+
They emit `DeprecationWarning` and must not be used by new internal code. They
|
|
131
|
+
will be removed only in an explicitly announced breaking release.
|
|
132
|
+
|
|
133
|
+
## Automated guardrails
|
|
134
|
+
|
|
135
|
+
`tests/test_architecture.py` parses internal imports and fails when a layer
|
|
136
|
+
introduces a forbidden outward dependency. The compatibility analyzer is the
|
|
137
|
+
only documented exception. New exceptions require an architectural decision and
|
|
138
|
+
must not be added merely to make the test pass.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Airflow authentication
|
|
2
|
+
|
|
3
|
+
FlowSense keeps Airflow authentication behind the `AirflowAuthProvider` port.
|
|
4
|
+
The collector does not need to know whether credentials come from Airflow,
|
|
5
|
+
a reverse proxy, a secret manager, or an external identity system.
|
|
6
|
+
|
|
7
|
+
## Built-in modes
|
|
8
|
+
|
|
9
|
+
### Airflow login token
|
|
10
|
+
|
|
11
|
+
This remains the default for Airflow 3 deployments that expose `/auth/token`:
|
|
12
|
+
|
|
13
|
+
```env
|
|
14
|
+
AIRFLOW_AUTH_MODE=token
|
|
15
|
+
AIRFLOW_USERNAME=airflow
|
|
16
|
+
AIRFLOW_PASSWORD=secret
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
FlowSense exchanges the credentials once and caches the returned bearer token
|
|
20
|
+
for the lifetime of the client.
|
|
21
|
+
|
|
22
|
+
### Basic authentication
|
|
23
|
+
|
|
24
|
+
Common Airflow 2 Stable REST API deployments can use:
|
|
25
|
+
|
|
26
|
+
```env
|
|
27
|
+
AIRFLOW_API_VERSION=v1
|
|
28
|
+
AIRFLOW_AUTH_MODE=basic
|
|
29
|
+
AIRFLOW_USERNAME=airflow
|
|
30
|
+
AIRFLOW_PASSWORD=secret
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Static bearer token
|
|
34
|
+
|
|
35
|
+
For deployments that issue a token outside Airflow:
|
|
36
|
+
|
|
37
|
+
```env
|
|
38
|
+
AIRFLOW_AUTH_MODE=bearer
|
|
39
|
+
AIRFLOW_BEARER_TOKEN=secret-token
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Username and password are not required in bearer mode. Secrets are excluded
|
|
43
|
+
from the `AirflowConfig` representation, but applications must still keep them
|
|
44
|
+
out of logs, shell history, source control, and command-line arguments.
|
|
45
|
+
|
|
46
|
+
## Custom provider
|
|
47
|
+
|
|
48
|
+
Enterprise integrations can inject an `AirflowAuthProvider` directly. This is
|
|
49
|
+
appropriate for rotating tokens, identity-aware proxies, workload identity, or
|
|
50
|
+
deployment-specific headers:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from flowsense.infrastructure.airflow import (
|
|
54
|
+
AirflowClient,
|
|
55
|
+
AirflowConfig,
|
|
56
|
+
HeaderAuthProvider,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
provider = HeaderAuthProvider({"X-Forwarded-User": "flowsense"})
|
|
60
|
+
client = AirflowClient(
|
|
61
|
+
AirflowConfig(base_url="https://airflow.example.com"),
|
|
62
|
+
auth_provider=provider,
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For rotating bearer credentials, pass a callable. It is evaluated for every
|
|
67
|
+
Airflow request:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from flowsense.infrastructure.airflow import BearerTokenAuthProvider
|
|
71
|
+
|
|
72
|
+
provider = BearerTokenAuthProvider(load_current_token)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Custom providers should return only authentication material and leave request
|
|
76
|
+
execution, retry, timeout, payload validation, and error translation to
|
|
77
|
+
`AirflowClient`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Performance benchmarks
|
|
2
|
+
|
|
3
|
+
FlowSense includes a deterministic synthetic benchmark for measuring the
|
|
4
|
+
default analysis engine independently from Airflow and network latency.
|
|
5
|
+
|
|
6
|
+
The benchmark creates an ordered chain DAG, generates repeatable task timings,
|
|
7
|
+
injects anomalies into the latest run, and reports:
|
|
8
|
+
|
|
9
|
+
- analysis execution time;
|
|
10
|
+
- total time including versioned output serialization;
|
|
11
|
+
- peak Python memory observed through `tracemalloc`;
|
|
12
|
+
- scenario dimensions and analyzed task count.
|
|
13
|
+
|
|
14
|
+
Run the default scenario:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv run python -m benchmarks.benchmark_analysis
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Run a larger scenario and save machine-readable results:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
uv run python -m benchmarks.benchmark_analysis \
|
|
24
|
+
--tasks 500 \
|
|
25
|
+
--runs 100 \
|
|
26
|
+
--iterations 5 \
|
|
27
|
+
--output benchmark-results.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The GitHub `Analysis benchmark` workflow provides the same parameters and
|
|
31
|
+
uploads the JSON result as a workflow artifact.
|
|
32
|
+
|
|
33
|
+
Benchmark results are observational and do not use hard pass/fail time limits.
|
|
34
|
+
Shared CI runners have variable performance, so fixed thresholds would create
|
|
35
|
+
flaky checks. Compare runs produced with the same scenario, Python version, and
|
|
36
|
+
similar hardware. Introduce performance gates only after a stable baseline has
|
|
37
|
+
been collected on controlled runners.
|