fastapi-alertengine 1.1.2__tar.gz → 1.1.4__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.
- fastapi_alertengine-1.1.4/.claude/settings.local.json +25 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/PKG-INFO +1 -1
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/examples/main.py +79 -97
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/fastapi_alertengine/__init__.py +53 -56
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/fastapi_alertengine/client.py +62 -65
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/fastapi_alertengine/config.py +37 -34
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/fastapi_alertengine/engine.py +191 -174
- fastapi_alertengine-1.1.4/fastapi_alertengine/middleware.py +59 -0
- fastapi_alertengine-1.1.4/fastapi_alertengine/schemas.py +12 -0
- fastapi_alertengine-1.1.4/fastapi_alertengine/storage.py +128 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/pyproject.toml +1 -1
- fastapi_alertengine-1.1.4/tests/test_engine_basic.py +187 -0
- fastapi_alertengine-1.1.2/.claude/settings.local.json +0 -17
- fastapi_alertengine-1.1.2/fastapi_alertengine/middleware.py +0 -64
- fastapi_alertengine-1.1.2/fastapi_alertengine/schemas.py +0 -52
- fastapi_alertengine-1.1.2/fastapi_alertengine/storage.py +0 -130
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/# +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/.env +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/.env.example +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/.git +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/.gitattributes +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/.gitignore +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/AnchorFlow_Explainer.mp4 +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/AnchorFlow_Explainer_Script.docx +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/AnchorFlow_Explainer_Script.pptx +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/COMPLETE SCHEMA DOCUMENTATION FOR CLAUDE REVIEW.docx +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/Dockerfile.api +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/LICENSE +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/README.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/REAL_TEST_EXECUTION_MANUAL.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/SKILL.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/TESTING ARCHITECTURE.docx +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/alembic.ini +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/anchorflow-fundrazr-campaign.html +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/anchorflow_logo.gif +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/anchorflow_script.js +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/anchorflow_script_word.js +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/anchorflow_video.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/ecocash_wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/fiscal_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/innbucks_wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/mock_fiscal_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/mock_wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/omari_wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/paynow_wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/twilio_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/zimra_fiscal+adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/adapters/zimra_fiscal_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/conversation_log.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/engine.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/handlers/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/handlers/browsing.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/handlers/courier_flow.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/handlers/ordering.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/handlers/payment_wait.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/locks.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/bot/state_manager.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/config.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/ai/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/ai/intake_ai.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/ai/vision_ai.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/alert_deduplicator.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/alert_engine.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/alert_notification_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/config.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/courier_fence.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/event_bus.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/events.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/idempotency.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/load_shedding.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/metrics.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/redis.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/redis_health.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/safe_redis.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/core/state_machine.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/dashboard/transaction_health.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/db.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/events/audit_event.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/events/index_health.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/jobs/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/jobs/alert_cleanup_job.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/jobs/escrow_timeout_job.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/jobs/low_stock_job.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/jobs/merchant_ack_job.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/maintenance/index_health.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/maintenance/key_cleanup.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/auth.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/health.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/notifications.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/routes.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/schemas.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/templates/dashboard.html +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/merchant_portal/templates/deal_detail.html +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/middleware/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/middleware/request_metrics.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/models/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/models/database.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/models/proof_of_delivery.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/notifications/rotation_alerts.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/recovery/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/recovery/stuck_detector.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/alert_router.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/dashboard_router.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/deals.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/escrow_health.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/hypercare_dashboard.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/inventory.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/merchant_portal.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/metrics_router.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/recovery.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/webhook_controller.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/routers/whatsapp_bot.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/security/auth.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/security/encryption.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/security/key_rotation.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/security/pii_handler.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/catalogue.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/courier_timeout_engine.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/deal_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/dispute_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/dual_write.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/escrow_timeout_engine.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/event_log_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/inventory_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/merchant_catalogue_local.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/merchant_experience.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/merchant_onboarding.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/order_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/proof_of_delivery_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/recovery_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/settlement_engine.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/services/trust_score_engine.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/startup/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/startup/health_check.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/templates/deal.html +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/app/templates/merchant_dashboard.html +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/config.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/database.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/decryption.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/API.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/ARCHITECTURE.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/CONFIG.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/DEPLOYMENT.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/HARDENING.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/OPERATIONS.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/SYSTEM_SPEC.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/docs/assets/tofamba_logo.png +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/git +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/main.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/001_add_currency_merchant_ack.sql +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/env.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/script.py.mako +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/20250311_001_baseline_schema.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/20250311_002_add_currency_merchant_ack_indexes.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/20250329_003_merchant_onboarding.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/20250401_003_merchant_onboarding_v2.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/20250402_004_buyer_flow_orders.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/20250402_005_rbz_compliance.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/20250407_006_alert_history.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/migrations/versions/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/pytest +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/railway.yaml +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/requirements.txt +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/security/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/security/pii_handler.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/security/pin_verification.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/services/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/services/catalogue.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/services/escrow_release.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/services/payment_ledger.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/services/payment_provider.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/README.md +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/__init__.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_alert_engine_enhancements.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_anchorflow_tasks.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_courier_fence.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_deal_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_escrow_timeout.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_idempotency.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_inventory_service.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_load_shedding.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_metrics.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_mock_fiscal_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_mock_wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_payment_adapters.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_paynow_wallet_adapter.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_recovery_sweep.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/tests/unit/test_safe_redis.py +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/workflows/tests.yml +0 -0
- {fastapi_alertengine-1.1.2 → fastapi_alertengine-1.1.4}/~$STING ARCHITECTURE.docx +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(python -m twine upload dist/fastapi_alertengine-1.1.1*)",
|
|
5
|
+
"Bash(rm -rf dist/)",
|
|
6
|
+
"Bash(python -m build)",
|
|
7
|
+
"Bash(gh pr create --title 'docs: replace README with polished production version + $49 starter pack CTA' --body ':*)",
|
|
8
|
+
"Bash(where gh:*)",
|
|
9
|
+
"Bash(mkdir -p /tmp/alertengine_test)",
|
|
10
|
+
"Read(//tmp/**)",
|
|
11
|
+
"Bash(python -m venv venv)",
|
|
12
|
+
"Bash(venv/Scripts/pip install:*)",
|
|
13
|
+
"Bash(venv/Scripts/python -c \"import fastapi_alertengine; print\\(dir\\(fastapi_alertengine\\)\\)\")",
|
|
14
|
+
"Bash(venv/Scripts/python test_suite.py)",
|
|
15
|
+
"Bash(python -m twine upload dist/fastapi_alertengine-1.1.2* -u __token__ -p \"pypi-AgEIcHlwaS5vcmcCJDY2YzU5ZDQ2LTc1MzYtNDBlMC05NmEwLWQzNjY1YWE0YzFmMwACKlszLCJkOGIzYzYyYi04ZjZhLTQ1Y2QtOGI0Yy04NjVkNTc3YzdiMzIiXQAABiCzHg3XIP-Fc19FHsOR-y7ODms4njBSo5IoiXTHJfzUaA\")",
|
|
16
|
+
"Bash(venv/Scripts/python -c ':*)",
|
|
17
|
+
"Read(//c/tmp/alertengine_test/**)",
|
|
18
|
+
"Bash(python -m twine upload dist/fastapi_alertengine-1.1.3* -u __token__ -p \"pypi-AgEIcHlwaS5vcmcCJDY2YzU5ZDQ2LTc1MzYtNDBlMC05NmEwLWQzNjY1YWE0YzFmMwACKlszLCJkOGIzYzYyYi04ZjZhLTQ1Y2QtOGI0Yy04NjVkNTc3YzdiMzIiXQAABiCzHg3XIP-Fc19FHsOR-y7ODms4njBSo5IoiXTHJfzUaA\")",
|
|
19
|
+
"Bash(python -m twine upload dist/fastapi_alertengine-1.1.3* -u __token__ -p \"pypi-AgEIcHlwaS5vcmcCJDY2YzU5ZDQ2LTc1MzYtNDBlMC05NmEwLWQzNjY1YWE0YzFmMwACKlszLCJkOGIzYzYyYi04ZjZhLTQ1Y2QtOGI0Yy04NjVkNTc3YzdiMzIiXQAABiCzHg3XIP-Fc19FHsOR-y7ODms4njBSo5IoiXTHJfzUaA\" --verbose)",
|
|
20
|
+
"Bash(venv/Scripts/python -m pytest \"C:/Users/HP/OneDrive/Documents/Tandem Hive/Tandem_Hive_V1_Final/.claude/worktrees/gracious-dubinsky/tests/test_engine_basic.py\" -v --tb=short --import-mode=importlib --pythonpath \"C:/Users/HP/OneDrive/Documents/Tandem Hive/Tandem_Hive_V1_Final/.claude/worktrees/gracious-dubinsky\")",
|
|
21
|
+
"Bash(PYTHONPATH=\"C:/Users/HP/OneDrive/Documents/Tandem Hive/Tandem_Hive_V1_Final/.claude/worktrees/gracious-dubinsky\" /tmp/alertengine_test/venv/Scripts/python -m pytest tests/test_engine_basic.py -v --tb=short)",
|
|
22
|
+
"Bash(python -m twine upload dist/fastapi_alertengine-1.1.4* -u __token__ -p \"pypi-AgEIcHlwaS5vcmcCJDY2YzU5ZDQ2LTc1MzYtNDBlMC05NmEwLWQzNjY1YWE0YzFmMwACKlszLCJkOGIzYzYyYi04ZjZhLTQ1Y2QtOGI0Yy04NjVkNTc3YzdiMzIiXQAABiCzHg3XIP-Fc19FHsOR-y7ODms4njBSo5IoiXTHJfzUaA\")"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-alertengine
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4
|
|
4
4
|
Summary: Production-grade request metrics middleware and SLO alert engine for FastAPI + Redis Streams
|
|
5
5
|
Project-URL: Homepage, https://anchorflow.com/tofamba
|
|
6
6
|
Project-URL: Repository, https://github.com/Tandem-Media/Tandem_Hive_V1_Final
|
|
@@ -1,97 +1,79 @@
|
|
|
1
|
-
# examples/main.py
|
|
2
|
-
"""
|
|
3
|
-
fastapi_alertengine — minimal demo app.
|
|
4
|
-
|
|
5
|
-
Three endpoints:
|
|
6
|
-
GET /fast — responds in ~5ms (normal traffic)
|
|
7
|
-
GET /slow — responds in ~600ms (triggers warning)
|
|
8
|
-
GET /error — returns HTTP 500 (drives up error rate)
|
|
9
|
-
|
|
10
|
-
Run:
|
|
11
|
-
pip install fastapi
|
|
12
|
-
redis-server &
|
|
13
|
-
uvicorn examples.main:app --reload
|
|
14
|
-
|
|
15
|
-
Then hit the endpoints a few times and check:
|
|
16
|
-
curl http://localhost:8000/alerts
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
import asyncio
|
|
20
|
-
import os
|
|
21
|
-
|
|
22
|
-
import redis
|
|
23
|
-
from fastapi import FastAPI
|
|
24
|
-
|
|
25
|
-
from fastapi_alertengine import (
|
|
26
|
-
AlertConfig,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# ── App ───────────────────────────────────────────────────────────────────────
|
|
39
|
-
|
|
40
|
-
app = FastAPI(title="fastapi_alertengine demo", version="
|
|
41
|
-
|
|
42
|
-
# Register metrics middleware — must come before any other middleware
|
|
43
|
-
app.add_middleware(RequestMetricsMiddleware,
|
|
44
|
-
|
|
45
|
-
# ── Demo endpoints ────────────────────────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
@app.get("/fast", tags=["demo"])
|
|
48
|
-
async def fast_endpoint():
|
|
49
|
-
"""Normal response — ~5ms latency."""
|
|
50
|
-
await asyncio.sleep(0.005)
|
|
51
|
-
return {"endpoint": "fast", "latency": "~5ms"}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
@app.get("/slow", tags=["demo"])
|
|
55
|
-
async def slow_endpoint():
|
|
56
|
-
"""Slow response — ~600ms latency, will push p95 into warning range."""
|
|
57
|
-
await asyncio.sleep(0.6)
|
|
58
|
-
return {"endpoint": "slow", "latency": "~600ms"}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
@app.get("/error", tags=["demo"])
|
|
62
|
-
async def error_endpoint():
|
|
63
|
-
"""Always returns 500 — drives up the error rate metric."""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
"status": event.status,
|
|
82
|
-
"reason": event.reason,
|
|
83
|
-
"metrics": {
|
|
84
|
-
"overall_p95_ms": event.metrics.overall_p95_ms,
|
|
85
|
-
"webhook_p95_ms": event.metrics.webhook_p95_ms,
|
|
86
|
-
"api_p95_ms": event.metrics.api_p95_ms,
|
|
87
|
-
"error_rate": event.metrics.error_rate,
|
|
88
|
-
"anomaly_score": event.metrics.anomaly_score,
|
|
89
|
-
"sample_size": event.metrics.sample_size,
|
|
90
|
-
},
|
|
91
|
-
"thresholds": {
|
|
92
|
-
"p95_warning_ms": event.thresholds.p95_warning_ms,
|
|
93
|
-
"p95_critical_ms": event.thresholds.p95_critical_ms,
|
|
94
|
-
"error_rate_critical": event.thresholds.error_rate_critical,
|
|
95
|
-
},
|
|
96
|
-
"aggregated": aggregate(rdb, AlertConfig()),
|
|
97
|
-
}
|
|
1
|
+
# examples/main.py
|
|
2
|
+
"""
|
|
3
|
+
fastapi_alertengine — minimal demo app.
|
|
4
|
+
|
|
5
|
+
Three endpoints:
|
|
6
|
+
GET /fast — responds in ~5ms (normal traffic)
|
|
7
|
+
GET /slow — responds in ~600ms (triggers warning)
|
|
8
|
+
GET /error — returns HTTP 500 (drives up error rate)
|
|
9
|
+
|
|
10
|
+
Run:
|
|
11
|
+
pip install "fastapi[standard]" redis fastapi-alertengine
|
|
12
|
+
redis-server &
|
|
13
|
+
uvicorn examples.main:app --reload
|
|
14
|
+
|
|
15
|
+
Then hit the endpoints a few times and check:
|
|
16
|
+
curl http://localhost:8000/alerts
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import asyncio
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
import redis
|
|
23
|
+
from fastapi import FastAPI, HTTPException
|
|
24
|
+
|
|
25
|
+
from fastapi_alertengine import (
|
|
26
|
+
AlertConfig,
|
|
27
|
+
RequestMetricsMiddleware,
|
|
28
|
+
aggregate,
|
|
29
|
+
get_alert_engine,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# ── Redis + engine ────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0")
|
|
35
|
+
rdb = redis.Redis.from_url(REDIS_URL, decode_responses=True)
|
|
36
|
+
engine = get_alert_engine(redis_client=rdb)
|
|
37
|
+
|
|
38
|
+
# ── App ───────────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
app = FastAPI(title="fastapi_alertengine demo", version="1.1.4")
|
|
41
|
+
|
|
42
|
+
# Register metrics middleware — must come before any other middleware
|
|
43
|
+
app.add_middleware(RequestMetricsMiddleware, alert_engine=engine)
|
|
44
|
+
|
|
45
|
+
# ── Demo endpoints ────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
@app.get("/fast", tags=["demo"])
|
|
48
|
+
async def fast_endpoint():
|
|
49
|
+
"""Normal response — ~5ms latency."""
|
|
50
|
+
await asyncio.sleep(0.005)
|
|
51
|
+
return {"endpoint": "fast", "latency": "~5ms"}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@app.get("/slow", tags=["demo"])
|
|
55
|
+
async def slow_endpoint():
|
|
56
|
+
"""Slow response — ~600ms latency, will push p95 into warning range."""
|
|
57
|
+
await asyncio.sleep(0.6)
|
|
58
|
+
return {"endpoint": "slow", "latency": "~600ms"}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@app.get("/error", tags=["demo"])
|
|
62
|
+
async def error_endpoint():
|
|
63
|
+
"""Always returns 500 — drives up the error rate metric."""
|
|
64
|
+
raise HTTPException(status_code=500, detail="Intentional error for demo")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# ── Alert status endpoint ─────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
@app.get("/alerts", tags=["observability"])
|
|
70
|
+
def alert_status():
|
|
71
|
+
"""
|
|
72
|
+
Evaluate current alert status from recent request metrics.
|
|
73
|
+
|
|
74
|
+
Returns the AlertEngine result plus a p95 breakdown by traffic type.
|
|
75
|
+
"""
|
|
76
|
+
return {
|
|
77
|
+
**engine.evaluate(window_size=200),
|
|
78
|
+
"aggregated": aggregate(rdb, engine.config),
|
|
79
|
+
}
|
|
@@ -1,56 +1,53 @@
|
|
|
1
|
-
# fastapi_alertengine/__init__.py
|
|
2
|
-
"""
|
|
3
|
-
fastapi_alertengine
|
|
4
|
-
===================
|
|
5
|
-
|
|
6
|
-
Production-grade request metrics middleware and SLO alert engine for
|
|
7
|
-
FastAPI services. Backed by Redis Streams.
|
|
8
|
-
|
|
9
|
-
Quick start::
|
|
10
|
-
|
|
11
|
-
from fastapi import FastAPI
|
|
12
|
-
from fastapi_alertengine import RequestMetricsMiddleware, get_alert_engine
|
|
13
|
-
import redis
|
|
14
|
-
|
|
15
|
-
app = FastAPI()
|
|
16
|
-
rdb = redis.Redis.from_url("redis://localhost:6379", decode_responses=True)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
from .
|
|
28
|
-
from .
|
|
29
|
-
from .
|
|
30
|
-
from .
|
|
31
|
-
from .
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
#
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
__version__ = _v("fastapi-alertengine")
|
|
55
|
-
except Exception:
|
|
56
|
-
__version__ = "unknown"
|
|
1
|
+
# fastapi_alertengine/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
fastapi_alertengine
|
|
4
|
+
===================
|
|
5
|
+
|
|
6
|
+
Production-grade request metrics middleware and SLO alert engine for
|
|
7
|
+
FastAPI services. Backed by Redis Streams.
|
|
8
|
+
|
|
9
|
+
Quick start::
|
|
10
|
+
|
|
11
|
+
from fastapi import FastAPI
|
|
12
|
+
from fastapi_alertengine import RequestMetricsMiddleware, get_alert_engine
|
|
13
|
+
import redis
|
|
14
|
+
|
|
15
|
+
app = FastAPI()
|
|
16
|
+
rdb = redis.Redis.from_url("redis://localhost:6379/0", decode_responses=True)
|
|
17
|
+
|
|
18
|
+
engine = get_alert_engine(redis_client=rdb)
|
|
19
|
+
app.add_middleware(RequestMetricsMiddleware, alert_engine=engine)
|
|
20
|
+
|
|
21
|
+
@app.get("/health/alerts")
|
|
22
|
+
def alert_status():
|
|
23
|
+
return engine.evaluate()
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from .client import get_alert_engine
|
|
27
|
+
from .config import AlertConfig
|
|
28
|
+
from .engine import AlertDeduplicator, AlertEngine
|
|
29
|
+
from .middleware import RequestMetricsMiddleware
|
|
30
|
+
from .schemas import RequestMetricEvent
|
|
31
|
+
from .storage import aggregate, p95, read_metrics, write_metric
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
from importlib.metadata import version as _v
|
|
35
|
+
__version__ = _v("fastapi-alertengine")
|
|
36
|
+
except Exception:
|
|
37
|
+
__version__ = "unknown"
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
# Primary surface
|
|
41
|
+
"RequestMetricsMiddleware",
|
|
42
|
+
"AlertEngine",
|
|
43
|
+
"AlertDeduplicator",
|
|
44
|
+
"get_alert_engine",
|
|
45
|
+
# Config + schemas
|
|
46
|
+
"AlertConfig",
|
|
47
|
+
"RequestMetricEvent",
|
|
48
|
+
# Storage helpers
|
|
49
|
+
"aggregate",
|
|
50
|
+
"p95",
|
|
51
|
+
"read_metrics",
|
|
52
|
+
"write_metric",
|
|
53
|
+
]
|
|
@@ -1,65 +1,62 @@
|
|
|
1
|
-
# fastapi_alertengine/client.py
|
|
2
|
-
"""
|
|
3
|
-
get_alert_engine() — process-level singleton factory.
|
|
4
|
-
|
|
5
|
-
Lazily constructs one AlertEngine per (redis_url, config) pair and
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Usage::
|
|
10
|
-
|
|
11
|
-
from fastapi_alertengine import get_alert_engine
|
|
12
|
-
|
|
13
|
-
engine = get_alert_engine(
|
|
14
|
-
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import threading
|
|
18
|
-
from typing import Optional
|
|
19
|
-
|
|
20
|
-
import redis as _redis_lib
|
|
21
|
-
|
|
22
|
-
from .config import AlertConfig
|
|
23
|
-
from .engine import AlertEngine
|
|
24
|
-
|
|
25
|
-
_lock = threading.Lock()
|
|
26
|
-
_registry: dict
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def get_alert_engine(
|
|
30
|
-
|
|
31
|
-
redis_client
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
``
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
redis_client: Pre-built ``redis.Redis`` instance (optional).
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
_registry[key] = AlertEngine(redis=rdb, config=cfg)
|
|
64
|
-
|
|
65
|
-
return _registry[key]
|
|
1
|
+
# fastapi_alertengine/client.py
|
|
2
|
+
"""
|
|
3
|
+
get_alert_engine() — process-level singleton factory.
|
|
4
|
+
|
|
5
|
+
Lazily constructs one AlertEngine per (redis_url, config) pair and caches it
|
|
6
|
+
for the lifetime of the process. Safe to call from anywhere without worrying
|
|
7
|
+
about duplicate Redis connections.
|
|
8
|
+
|
|
9
|
+
Usage::
|
|
10
|
+
|
|
11
|
+
from fastapi_alertengine import get_alert_engine
|
|
12
|
+
|
|
13
|
+
engine = get_alert_engine(redis_client=rdb)
|
|
14
|
+
result = engine.evaluate()
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import threading
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
import redis as _redis_lib
|
|
21
|
+
|
|
22
|
+
from .config import AlertConfig
|
|
23
|
+
from .engine import AlertEngine
|
|
24
|
+
|
|
25
|
+
_lock: threading.Lock = threading.Lock()
|
|
26
|
+
_registry: dict = {}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_alert_engine(
|
|
30
|
+
config: Optional[AlertConfig] = None,
|
|
31
|
+
redis_client = None,
|
|
32
|
+
) -> AlertEngine:
|
|
33
|
+
"""
|
|
34
|
+
Return a cached :class:`~fastapi_alertengine.engine.AlertEngine`.
|
|
35
|
+
|
|
36
|
+
Pass an already-constructed ``redis_client`` to reuse an existing
|
|
37
|
+
connection. If omitted, a new client is created from
|
|
38
|
+
``config.redis_url``.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
config: :class:`~fastapi_alertengine.config.AlertConfig`.
|
|
42
|
+
Defaults to ``AlertConfig()`` (all library defaults).
|
|
43
|
+
redis_client: Pre-built ``redis.Redis`` instance (optional).
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
A shared :class:`~fastapi_alertengine.engine.AlertEngine` instance.
|
|
47
|
+
"""
|
|
48
|
+
cfg = config or AlertConfig()
|
|
49
|
+
key = id(redis_client) if redis_client is not None else cfg.redis_url
|
|
50
|
+
|
|
51
|
+
if key not in _registry:
|
|
52
|
+
with _lock:
|
|
53
|
+
if key not in _registry:
|
|
54
|
+
rdb = redis_client or _redis_lib.Redis.from_url(
|
|
55
|
+
cfg.redis_url,
|
|
56
|
+
decode_responses=True,
|
|
57
|
+
socket_timeout=5,
|
|
58
|
+
socket_connect_timeout=5,
|
|
59
|
+
)
|
|
60
|
+
_registry[key] = AlertEngine(redis=rdb, config=cfg)
|
|
61
|
+
|
|
62
|
+
return _registry[key]
|
|
@@ -1,34 +1,37 @@
|
|
|
1
|
-
# fastapi_alertengine/config.py
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@dataclass
|
|
6
|
-
class AlertConfig:
|
|
7
|
-
"""
|
|
8
|
-
All tunable parameters for the alert engine in one place.
|
|
9
|
-
|
|
10
|
-
Pass a custom instance to
|
|
11
|
-
to override any default without subclassing.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
# ── Redis
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# ──
|
|
34
|
-
|
|
1
|
+
# fastapi_alertengine/config.py
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class AlertConfig:
|
|
7
|
+
"""
|
|
8
|
+
All tunable parameters for the alert engine in one place.
|
|
9
|
+
|
|
10
|
+
Pass a custom instance to get_alert_engine() or AlertEngine()
|
|
11
|
+
to override any default without subclassing.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# ── Redis connection ──────────────────────────────────────────────────────
|
|
15
|
+
redis_url: str = "redis://localhost:6379/0"
|
|
16
|
+
|
|
17
|
+
# ── Redis Stream ──────────────────────────────────────────────────────────
|
|
18
|
+
stream_key: str = "anchorflow:request_metrics"
|
|
19
|
+
stream_maxlen: int = 10_000 # approximate cap (Redis MAXLEN ~)
|
|
20
|
+
|
|
21
|
+
# ── Latency thresholds (ms) ───────────────────────────────────────────────
|
|
22
|
+
p95_warning_ms: float = 1_000.0
|
|
23
|
+
p95_critical_ms: float = 3_000.0
|
|
24
|
+
|
|
25
|
+
# ── Anomaly thresholds (ratio vs rolling mean) ────────────────────────────
|
|
26
|
+
anomaly_warning: float = 1.0
|
|
27
|
+
anomaly_critical: float = 2.0
|
|
28
|
+
|
|
29
|
+
# ── Error-rate thresholds (fraction of 5xx responses) ────────────────────
|
|
30
|
+
error_rate_warning: float = 0.10
|
|
31
|
+
error_rate_critical: float = 0.20
|
|
32
|
+
|
|
33
|
+
# ── Evaluation window ─────────────────────────────────────────────────────
|
|
34
|
+
window_size: int = 200 # events read per evaluate() call
|
|
35
|
+
|
|
36
|
+
# ── Deduplication ─────────────────────────────────────────────────────────
|
|
37
|
+
cooldown_seconds: int = 300 # min seconds between identical alerts
|