tapps-agents 3.5.40__py3-none-any.whl → 3.6.0__py3-none-any.whl
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.
- tapps_agents/__init__.py +2 -2
- tapps_agents/agents/__init__.py +22 -22
- tapps_agents/agents/analyst/__init__.py +5 -5
- tapps_agents/agents/architect/__init__.py +5 -5
- tapps_agents/agents/architect/agent.py +1033 -1033
- tapps_agents/agents/architect/pattern_detector.py +75 -75
- tapps_agents/agents/cleanup/__init__.py +7 -7
- tapps_agents/agents/cleanup/agent.py +445 -445
- tapps_agents/agents/debugger/__init__.py +7 -7
- tapps_agents/agents/debugger/agent.py +310 -310
- tapps_agents/agents/debugger/error_analyzer.py +437 -437
- tapps_agents/agents/designer/__init__.py +5 -5
- tapps_agents/agents/designer/agent.py +786 -786
- tapps_agents/agents/designer/visual_designer.py +638 -638
- tapps_agents/agents/documenter/__init__.py +7 -7
- tapps_agents/agents/documenter/agent.py +531 -531
- tapps_agents/agents/documenter/doc_generator.py +472 -472
- tapps_agents/agents/documenter/doc_validator.py +393 -393
- tapps_agents/agents/documenter/framework_doc_updater.py +493 -493
- tapps_agents/agents/enhancer/__init__.py +7 -7
- tapps_agents/agents/evaluator/__init__.py +7 -7
- tapps_agents/agents/evaluator/agent.py +443 -443
- tapps_agents/agents/evaluator/priority_evaluator.py +641 -641
- tapps_agents/agents/evaluator/quality_analyzer.py +147 -147
- tapps_agents/agents/evaluator/report_generator.py +344 -344
- tapps_agents/agents/evaluator/usage_analyzer.py +192 -192
- tapps_agents/agents/evaluator/workflow_analyzer.py +189 -189
- tapps_agents/agents/implementer/__init__.py +7 -7
- tapps_agents/agents/implementer/agent.py +798 -798
- tapps_agents/agents/implementer/auto_fix.py +1119 -1119
- tapps_agents/agents/implementer/code_generator.py +73 -73
- tapps_agents/agents/improver/__init__.py +1 -1
- tapps_agents/agents/improver/agent.py +753 -753
- tapps_agents/agents/ops/__init__.py +1 -1
- tapps_agents/agents/ops/agent.py +619 -619
- tapps_agents/agents/ops/dependency_analyzer.py +600 -600
- tapps_agents/agents/orchestrator/__init__.py +5 -5
- tapps_agents/agents/orchestrator/agent.py +522 -522
- tapps_agents/agents/planner/__init__.py +7 -7
- tapps_agents/agents/planner/agent.py +1127 -1127
- tapps_agents/agents/reviewer/__init__.py +24 -24
- tapps_agents/agents/reviewer/agent.py +3513 -3513
- tapps_agents/agents/reviewer/aggregator.py +213 -213
- tapps_agents/agents/reviewer/batch_review.py +448 -448
- tapps_agents/agents/reviewer/cache.py +443 -443
- tapps_agents/agents/reviewer/context7_enhancer.py +630 -630
- tapps_agents/agents/reviewer/context_detector.py +203 -203
- tapps_agents/agents/reviewer/docker_compose_validator.py +158 -158
- tapps_agents/agents/reviewer/dockerfile_validator.py +176 -176
- tapps_agents/agents/reviewer/error_handling.py +126 -126
- tapps_agents/agents/reviewer/feedback_generator.py +490 -490
- tapps_agents/agents/reviewer/influxdb_validator.py +316 -316
- tapps_agents/agents/reviewer/issue_tracking.py +169 -169
- tapps_agents/agents/reviewer/library_detector.py +295 -295
- tapps_agents/agents/reviewer/library_patterns.py +268 -268
- tapps_agents/agents/reviewer/maintainability_scorer.py +593 -593
- tapps_agents/agents/reviewer/metric_strategies.py +276 -276
- tapps_agents/agents/reviewer/mqtt_validator.py +160 -160
- tapps_agents/agents/reviewer/output_enhancer.py +105 -105
- tapps_agents/agents/reviewer/pattern_detector.py +241 -241
- tapps_agents/agents/reviewer/performance_scorer.py +357 -357
- tapps_agents/agents/reviewer/phased_review.py +516 -516
- tapps_agents/agents/reviewer/progressive_review.py +435 -435
- tapps_agents/agents/reviewer/react_scorer.py +331 -331
- tapps_agents/agents/reviewer/score_constants.py +228 -228
- tapps_agents/agents/reviewer/score_validator.py +507 -507
- tapps_agents/agents/reviewer/scorer_registry.py +373 -373
- tapps_agents/agents/reviewer/scoring.py +1566 -1566
- tapps_agents/agents/reviewer/service_discovery.py +534 -534
- tapps_agents/agents/reviewer/tools/__init__.py +41 -41
- tapps_agents/agents/reviewer/tools/parallel_executor.py +581 -581
- tapps_agents/agents/reviewer/tools/ruff_grouping.py +250 -250
- tapps_agents/agents/reviewer/tools/scoped_mypy.py +284 -284
- tapps_agents/agents/reviewer/typescript_scorer.py +1142 -1142
- tapps_agents/agents/reviewer/validation.py +208 -208
- tapps_agents/agents/reviewer/websocket_validator.py +132 -132
- tapps_agents/agents/tester/__init__.py +7 -7
- tapps_agents/agents/tester/accessibility_auditor.py +309 -309
- tapps_agents/agents/tester/agent.py +1080 -1080
- tapps_agents/agents/tester/batch_generator.py +54 -54
- tapps_agents/agents/tester/context_learner.py +51 -51
- tapps_agents/agents/tester/coverage_analyzer.py +386 -386
- tapps_agents/agents/tester/coverage_test_generator.py +290 -290
- tapps_agents/agents/tester/debug_enhancer.py +238 -238
- tapps_agents/agents/tester/device_emulator.py +241 -241
- tapps_agents/agents/tester/integration_generator.py +62 -62
- tapps_agents/agents/tester/network_recorder.py +300 -300
- tapps_agents/agents/tester/performance_monitor.py +320 -320
- tapps_agents/agents/tester/test_fixer.py +316 -316
- tapps_agents/agents/tester/test_generator.py +632 -632
- tapps_agents/agents/tester/trace_manager.py +234 -234
- tapps_agents/agents/tester/visual_regression.py +291 -291
- tapps_agents/analysis/pattern_detector.py +36 -36
- tapps_agents/beads/hydration.py +213 -213
- tapps_agents/beads/parse.py +32 -32
- tapps_agents/beads/specs.py +206 -206
- tapps_agents/cli/__init__.py +9 -9
- tapps_agents/cli/__main__.py +8 -8
- tapps_agents/cli/base.py +478 -478
- tapps_agents/cli/command_classifier.py +72 -72
- tapps_agents/cli/commands/__init__.py +2 -2
- tapps_agents/cli/commands/analyst.py +173 -173
- tapps_agents/cli/commands/architect.py +109 -109
- tapps_agents/cli/commands/cleanup_agent.py +92 -92
- tapps_agents/cli/commands/common.py +126 -126
- tapps_agents/cli/commands/debugger.py +90 -90
- tapps_agents/cli/commands/designer.py +112 -112
- tapps_agents/cli/commands/documenter.py +136 -136
- tapps_agents/cli/commands/enhancer.py +110 -110
- tapps_agents/cli/commands/evaluator.py +255 -255
- tapps_agents/cli/commands/health.py +665 -665
- tapps_agents/cli/commands/implementer.py +301 -301
- tapps_agents/cli/commands/improver.py +91 -91
- tapps_agents/cli/commands/knowledge.py +111 -111
- tapps_agents/cli/commands/learning.py +172 -172
- tapps_agents/cli/commands/observability.py +283 -283
- tapps_agents/cli/commands/ops.py +135 -135
- tapps_agents/cli/commands/orchestrator.py +116 -116
- tapps_agents/cli/commands/planner.py +237 -237
- tapps_agents/cli/commands/reviewer.py +1872 -1872
- tapps_agents/cli/commands/status.py +285 -285
- tapps_agents/cli/commands/task.py +227 -219
- tapps_agents/cli/commands/tester.py +191 -191
- tapps_agents/cli/commands/top_level.py +3586 -3586
- tapps_agents/cli/feedback.py +936 -936
- tapps_agents/cli/formatters.py +608 -608
- tapps_agents/cli/help/__init__.py +7 -7
- tapps_agents/cli/help/static_help.py +425 -425
- tapps_agents/cli/network_detection.py +110 -110
- tapps_agents/cli/output_compactor.py +274 -274
- tapps_agents/cli/parsers/__init__.py +2 -2
- tapps_agents/cli/parsers/analyst.py +186 -186
- tapps_agents/cli/parsers/architect.py +167 -167
- tapps_agents/cli/parsers/cleanup_agent.py +228 -228
- tapps_agents/cli/parsers/debugger.py +116 -116
- tapps_agents/cli/parsers/designer.py +182 -182
- tapps_agents/cli/parsers/documenter.py +134 -134
- tapps_agents/cli/parsers/enhancer.py +113 -113
- tapps_agents/cli/parsers/evaluator.py +213 -213
- tapps_agents/cli/parsers/implementer.py +168 -168
- tapps_agents/cli/parsers/improver.py +132 -132
- tapps_agents/cli/parsers/ops.py +159 -159
- tapps_agents/cli/parsers/orchestrator.py +98 -98
- tapps_agents/cli/parsers/planner.py +145 -145
- tapps_agents/cli/parsers/reviewer.py +462 -462
- tapps_agents/cli/parsers/tester.py +124 -124
- tapps_agents/cli/progress_heartbeat.py +254 -254
- tapps_agents/cli/streaming_progress.py +336 -336
- tapps_agents/cli/utils/__init__.py +6 -6
- tapps_agents/cli/utils/agent_lifecycle.py +48 -48
- tapps_agents/cli/utils/error_formatter.py +82 -82
- tapps_agents/cli/utils/error_recovery.py +188 -188
- tapps_agents/cli/utils/output_handler.py +59 -59
- tapps_agents/cli/utils/prompt_enhancer.py +319 -319
- tapps_agents/cli/validators/__init__.py +9 -9
- tapps_agents/cli/validators/command_validator.py +81 -81
- tapps_agents/context7/__init__.py +112 -112
- tapps_agents/context7/agent_integration.py +869 -869
- tapps_agents/context7/analytics.py +382 -382
- tapps_agents/context7/analytics_dashboard.py +299 -299
- tapps_agents/context7/async_cache.py +681 -681
- tapps_agents/context7/backup_client.py +958 -958
- tapps_agents/context7/cache_locking.py +194 -194
- tapps_agents/context7/cache_metadata.py +214 -214
- tapps_agents/context7/cache_prewarm.py +488 -488
- tapps_agents/context7/cache_structure.py +168 -168
- tapps_agents/context7/cache_warming.py +604 -604
- tapps_agents/context7/circuit_breaker.py +376 -376
- tapps_agents/context7/cleanup.py +461 -461
- tapps_agents/context7/commands.py +858 -858
- tapps_agents/context7/credential_validation.py +276 -276
- tapps_agents/context7/cross_reference_resolver.py +168 -168
- tapps_agents/context7/cross_references.py +424 -424
- tapps_agents/context7/doc_manager.py +225 -225
- tapps_agents/context7/fuzzy_matcher.py +369 -369
- tapps_agents/context7/kb_cache.py +404 -404
- tapps_agents/context7/language_detector.py +219 -219
- tapps_agents/context7/library_detector.py +725 -725
- tapps_agents/context7/lookup.py +738 -738
- tapps_agents/context7/metadata.py +258 -258
- tapps_agents/context7/refresh_queue.py +300 -300
- tapps_agents/context7/security.py +373 -373
- tapps_agents/context7/staleness_policies.py +278 -278
- tapps_agents/context7/tiles_integration.py +47 -47
- tapps_agents/continuous_bug_fix/__init__.py +20 -20
- tapps_agents/continuous_bug_fix/bug_finder.py +306 -306
- tapps_agents/continuous_bug_fix/bug_fix_coordinator.py +177 -177
- tapps_agents/continuous_bug_fix/commit_manager.py +178 -178
- tapps_agents/continuous_bug_fix/continuous_bug_fixer.py +322 -322
- tapps_agents/continuous_bug_fix/proactive_bug_finder.py +285 -285
- tapps_agents/core/__init__.py +298 -298
- tapps_agents/core/adaptive_cache_config.py +432 -432
- tapps_agents/core/agent_base.py +647 -647
- tapps_agents/core/agent_cache.py +466 -466
- tapps_agents/core/agent_learning.py +1865 -1865
- tapps_agents/core/analytics_dashboard.py +563 -563
- tapps_agents/core/analytics_enhancements.py +597 -597
- tapps_agents/core/anonymization.py +274 -274
- tapps_agents/core/artifact_context_builder.py +293 -0
- tapps_agents/core/ast_parser.py +228 -228
- tapps_agents/core/async_file_ops.py +402 -402
- tapps_agents/core/best_practice_consultant.py +299 -299
- tapps_agents/core/brownfield_analyzer.py +299 -299
- tapps_agents/core/brownfield_review.py +541 -541
- tapps_agents/core/browser_controller.py +513 -513
- tapps_agents/core/capability_registry.py +418 -418
- tapps_agents/core/change_impact_analyzer.py +190 -190
- tapps_agents/core/checkpoint_manager.py +377 -377
- tapps_agents/core/code_generator.py +329 -329
- tapps_agents/core/code_validator.py +276 -276
- tapps_agents/core/command_registry.py +327 -327
- tapps_agents/core/config.py +33 -0
- tapps_agents/core/context_gathering/__init__.py +2 -2
- tapps_agents/core/context_gathering/repository_explorer.py +28 -28
- tapps_agents/core/context_intelligence/__init__.py +2 -2
- tapps_agents/core/context_intelligence/relevance_scorer.py +24 -24
- tapps_agents/core/context_intelligence/token_budget_manager.py +27 -27
- tapps_agents/core/context_manager.py +240 -240
- tapps_agents/core/cursor_feedback_monitor.py +146 -146
- tapps_agents/core/cursor_verification.py +290 -290
- tapps_agents/core/customization_loader.py +280 -280
- tapps_agents/core/customization_schema.py +260 -260
- tapps_agents/core/customization_template.py +238 -238
- tapps_agents/core/debug_logger.py +124 -124
- tapps_agents/core/design_validator.py +298 -298
- tapps_agents/core/diagram_generator.py +226 -226
- tapps_agents/core/docker_utils.py +232 -232
- tapps_agents/core/document_generator.py +617 -617
- tapps_agents/core/domain_detector.py +30 -30
- tapps_agents/core/error_envelope.py +454 -454
- tapps_agents/core/error_handler.py +270 -270
- tapps_agents/core/estimation_tracker.py +189 -189
- tapps_agents/core/eval_prompt_engine.py +116 -116
- tapps_agents/core/evaluation_base.py +119 -119
- tapps_agents/core/evaluation_models.py +320 -320
- tapps_agents/core/evaluation_orchestrator.py +225 -225
- tapps_agents/core/evaluators/__init__.py +7 -7
- tapps_agents/core/evaluators/architectural_evaluator.py +205 -205
- tapps_agents/core/evaluators/behavioral_evaluator.py +160 -160
- tapps_agents/core/evaluators/performance_profile_evaluator.py +160 -160
- tapps_agents/core/evaluators/security_posture_evaluator.py +148 -148
- tapps_agents/core/evaluators/spec_compliance_evaluator.py +181 -181
- tapps_agents/core/exceptions.py +107 -107
- tapps_agents/core/expert_config_generator.py +293 -293
- tapps_agents/core/export_schema.py +202 -202
- tapps_agents/core/external_feedback_models.py +102 -102
- tapps_agents/core/external_feedback_storage.py +213 -213
- tapps_agents/core/fallback_strategy.py +314 -314
- tapps_agents/core/feedback_analyzer.py +162 -162
- tapps_agents/core/feedback_collector.py +178 -178
- tapps_agents/core/git_operations.py +445 -445
- tapps_agents/core/hardware_profiler.py +151 -151
- tapps_agents/core/instructions.py +324 -324
- tapps_agents/core/io_guardrails.py +69 -69
- tapps_agents/core/issue_manifest.py +249 -249
- tapps_agents/core/issue_schema.py +139 -139
- tapps_agents/core/json_utils.py +128 -128
- tapps_agents/core/knowledge_graph.py +446 -446
- tapps_agents/core/language_detector.py +296 -296
- tapps_agents/core/learning_confidence.py +242 -242
- tapps_agents/core/learning_dashboard.py +246 -246
- tapps_agents/core/learning_decision.py +384 -384
- tapps_agents/core/learning_explainability.py +578 -578
- tapps_agents/core/learning_export.py +287 -287
- tapps_agents/core/learning_integration.py +228 -228
- tapps_agents/core/llm_behavior.py +232 -232
- tapps_agents/core/long_duration_support.py +786 -786
- tapps_agents/core/mcp_setup.py +106 -106
- tapps_agents/core/memory_integration.py +396 -396
- tapps_agents/core/meta_learning.py +666 -666
- tapps_agents/core/module_path_sanitizer.py +199 -199
- tapps_agents/core/multi_agent_orchestrator.py +382 -382
- tapps_agents/core/network_errors.py +125 -125
- tapps_agents/core/nfr_validator.py +336 -336
- tapps_agents/core/offline_mode.py +158 -158
- tapps_agents/core/output_contracts.py +300 -300
- tapps_agents/core/output_formatter.py +300 -300
- tapps_agents/core/path_normalizer.py +174 -174
- tapps_agents/core/path_validator.py +322 -322
- tapps_agents/core/pattern_library.py +250 -250
- tapps_agents/core/performance_benchmark.py +301 -301
- tapps_agents/core/performance_monitor.py +184 -184
- tapps_agents/core/playwright_mcp_controller.py +771 -771
- tapps_agents/core/policy_loader.py +135 -135
- tapps_agents/core/progress.py +166 -166
- tapps_agents/core/project_profile.py +354 -354
- tapps_agents/core/project_type_detector.py +454 -454
- tapps_agents/core/prompt_base.py +223 -223
- tapps_agents/core/prompt_learning/__init__.py +2 -2
- tapps_agents/core/prompt_learning/learning_loop.py +24 -24
- tapps_agents/core/prompt_learning/project_prompt_store.py +25 -25
- tapps_agents/core/prompt_learning/skills_prompt_analyzer.py +35 -35
- tapps_agents/core/prompt_optimization/__init__.py +6 -6
- tapps_agents/core/prompt_optimization/ab_tester.py +114 -114
- tapps_agents/core/prompt_optimization/correlation_analyzer.py +160 -160
- tapps_agents/core/prompt_optimization/progressive_refiner.py +129 -129
- tapps_agents/core/prompt_optimization/prompt_library.py +37 -37
- tapps_agents/core/requirements_evaluator.py +431 -431
- tapps_agents/core/resource_aware_executor.py +449 -449
- tapps_agents/core/resource_monitor.py +343 -343
- tapps_agents/core/resume_handler.py +298 -298
- tapps_agents/core/retry_handler.py +197 -197
- tapps_agents/core/review_checklists.py +479 -479
- tapps_agents/core/role_loader.py +201 -201
- tapps_agents/core/role_template_loader.py +201 -201
- tapps_agents/core/runtime_mode.py +60 -60
- tapps_agents/core/security_scanner.py +342 -342
- tapps_agents/core/skill_agent_registry.py +194 -194
- tapps_agents/core/skill_integration.py +208 -208
- tapps_agents/core/skill_loader.py +492 -492
- tapps_agents/core/skill_template.py +341 -341
- tapps_agents/core/skill_validator.py +478 -478
- tapps_agents/core/stack_analyzer.py +35 -35
- tapps_agents/core/startup.py +174 -174
- tapps_agents/core/storage_manager.py +397 -397
- tapps_agents/core/storage_models.py +166 -166
- tapps_agents/core/story_evaluator.py +410 -410
- tapps_agents/core/subprocess_utils.py +170 -170
- tapps_agents/core/task_duration.py +296 -296
- tapps_agents/core/task_memory.py +582 -582
- tapps_agents/core/task_state.py +226 -226
- tapps_agents/core/tech_stack_priorities.py +208 -208
- tapps_agents/core/temp_directory.py +194 -194
- tapps_agents/core/template_merger.py +600 -600
- tapps_agents/core/template_selector.py +280 -280
- tapps_agents/core/test_generator.py +286 -286
- tapps_agents/core/tiered_context.py +253 -253
- tapps_agents/core/token_monitor.py +345 -345
- tapps_agents/core/traceability.py +254 -254
- tapps_agents/core/trajectory_tracker.py +50 -50
- tapps_agents/core/unicode_safe.py +143 -143
- tapps_agents/core/unified_cache_config.py +170 -170
- tapps_agents/core/unified_state.py +324 -324
- tapps_agents/core/validate_cursor_setup.py +237 -237
- tapps_agents/core/validation_registry.py +136 -136
- tapps_agents/core/validators/__init__.py +4 -4
- tapps_agents/core/validators/python_validator.py +87 -87
- tapps_agents/core/verification_agent.py +90 -90
- tapps_agents/core/visual_feedback.py +644 -644
- tapps_agents/core/workflow_validator.py +197 -197
- tapps_agents/core/worktree.py +367 -367
- tapps_agents/docker/__init__.py +10 -10
- tapps_agents/docker/analyzer.py +186 -186
- tapps_agents/docker/debugger.py +229 -229
- tapps_agents/docker/error_patterns.py +216 -216
- tapps_agents/epic/__init__.py +22 -22
- tapps_agents/epic/beads_sync.py +115 -115
- tapps_agents/epic/markdown_sync.py +105 -105
- tapps_agents/epic/models.py +96 -96
- tapps_agents/experts/__init__.py +163 -163
- tapps_agents/experts/agent_integration.py +243 -243
- tapps_agents/experts/auto_generator.py +331 -331
- tapps_agents/experts/base_expert.py +536 -536
- tapps_agents/experts/builtin_registry.py +261 -261
- tapps_agents/experts/business_metrics.py +565 -565
- tapps_agents/experts/cache.py +266 -266
- tapps_agents/experts/confidence_breakdown.py +306 -306
- tapps_agents/experts/confidence_calculator.py +336 -336
- tapps_agents/experts/confidence_metrics.py +236 -236
- tapps_agents/experts/domain_config.py +311 -311
- tapps_agents/experts/domain_detector.py +550 -550
- tapps_agents/experts/domain_utils.py +84 -84
- tapps_agents/experts/expert_config.py +113 -113
- tapps_agents/experts/expert_engine.py +465 -465
- tapps_agents/experts/expert_registry.py +744 -744
- tapps_agents/experts/expert_synthesizer.py +70 -70
- tapps_agents/experts/governance.py +197 -197
- tapps_agents/experts/history_logger.py +312 -312
- tapps_agents/experts/knowledge/README.md +180 -180
- tapps_agents/experts/knowledge/accessibility/accessible-forms.md +331 -331
- tapps_agents/experts/knowledge/accessibility/aria-patterns.md +344 -344
- tapps_agents/experts/knowledge/accessibility/color-contrast.md +285 -285
- tapps_agents/experts/knowledge/accessibility/keyboard-navigation.md +332 -332
- tapps_agents/experts/knowledge/accessibility/screen-readers.md +282 -282
- tapps_agents/experts/knowledge/accessibility/semantic-html.md +355 -355
- tapps_agents/experts/knowledge/accessibility/testing-accessibility.md +369 -369
- tapps_agents/experts/knowledge/accessibility/wcag-2.1.md +296 -296
- tapps_agents/experts/knowledge/accessibility/wcag-2.2.md +211 -211
- tapps_agents/experts/knowledge/agent-learning/best-practices.md +715 -715
- tapps_agents/experts/knowledge/agent-learning/pattern-extraction.md +282 -282
- tapps_agents/experts/knowledge/agent-learning/prompt-optimization.md +320 -320
- tapps_agents/experts/knowledge/ai-frameworks/model-optimization.md +90 -90
- tapps_agents/experts/knowledge/ai-frameworks/openvino-patterns.md +260 -260
- tapps_agents/experts/knowledge/api-design-integration/api-gateway-patterns.md +309 -309
- tapps_agents/experts/knowledge/api-design-integration/api-security-patterns.md +521 -521
- tapps_agents/experts/knowledge/api-design-integration/api-versioning.md +421 -421
- tapps_agents/experts/knowledge/api-design-integration/async-protocol-patterns.md +61 -61
- tapps_agents/experts/knowledge/api-design-integration/contract-testing.md +221 -221
- tapps_agents/experts/knowledge/api-design-integration/external-api-integration.md +489 -489
- tapps_agents/experts/knowledge/api-design-integration/fastapi-patterns.md +360 -360
- tapps_agents/experts/knowledge/api-design-integration/fastapi-testing.md +262 -262
- tapps_agents/experts/knowledge/api-design-integration/graphql-patterns.md +582 -582
- tapps_agents/experts/knowledge/api-design-integration/grpc-best-practices.md +499 -499
- tapps_agents/experts/knowledge/api-design-integration/mqtt-patterns.md +455 -455
- tapps_agents/experts/knowledge/api-design-integration/rate-limiting.md +507 -507
- tapps_agents/experts/knowledge/api-design-integration/restful-api-design.md +618 -618
- tapps_agents/experts/knowledge/api-design-integration/websocket-patterns.md +480 -480
- tapps_agents/experts/knowledge/cloud-infrastructure/cloud-native-patterns.md +175 -175
- tapps_agents/experts/knowledge/cloud-infrastructure/container-health-checks.md +261 -261
- tapps_agents/experts/knowledge/cloud-infrastructure/containerization.md +222 -222
- tapps_agents/experts/knowledge/cloud-infrastructure/cost-optimization.md +122 -122
- tapps_agents/experts/knowledge/cloud-infrastructure/disaster-recovery.md +153 -153
- tapps_agents/experts/knowledge/cloud-infrastructure/dockerfile-patterns.md +285 -285
- tapps_agents/experts/knowledge/cloud-infrastructure/infrastructure-as-code.md +187 -187
- tapps_agents/experts/knowledge/cloud-infrastructure/kubernetes-patterns.md +253 -253
- tapps_agents/experts/knowledge/cloud-infrastructure/multi-cloud-strategies.md +155 -155
- tapps_agents/experts/knowledge/cloud-infrastructure/serverless-architecture.md +200 -200
- tapps_agents/experts/knowledge/code-quality-analysis/README.md +16 -16
- tapps_agents/experts/knowledge/code-quality-analysis/code-metrics.md +137 -137
- tapps_agents/experts/knowledge/code-quality-analysis/complexity-analysis.md +181 -181
- tapps_agents/experts/knowledge/code-quality-analysis/technical-debt-patterns.md +191 -191
- tapps_agents/experts/knowledge/data-privacy-compliance/anonymization.md +313 -313
- tapps_agents/experts/knowledge/data-privacy-compliance/ccpa.md +255 -255
- tapps_agents/experts/knowledge/data-privacy-compliance/consent-management.md +282 -282
- tapps_agents/experts/knowledge/data-privacy-compliance/data-minimization.md +275 -275
- tapps_agents/experts/knowledge/data-privacy-compliance/data-retention.md +297 -297
- tapps_agents/experts/knowledge/data-privacy-compliance/data-subject-rights.md +383 -383
- tapps_agents/experts/knowledge/data-privacy-compliance/encryption-privacy.md +285 -285
- tapps_agents/experts/knowledge/data-privacy-compliance/gdpr.md +344 -344
- tapps_agents/experts/knowledge/data-privacy-compliance/hipaa.md +385 -385
- tapps_agents/experts/knowledge/data-privacy-compliance/privacy-by-design.md +280 -280
- tapps_agents/experts/knowledge/database-data-management/acid-vs-cap.md +164 -164
- tapps_agents/experts/knowledge/database-data-management/backup-and-recovery.md +182 -182
- tapps_agents/experts/knowledge/database-data-management/data-modeling.md +172 -172
- tapps_agents/experts/knowledge/database-data-management/database-design.md +187 -187
- tapps_agents/experts/knowledge/database-data-management/flux-query-optimization.md +342 -342
- tapps_agents/experts/knowledge/database-data-management/influxdb-connection-patterns.md +432 -432
- tapps_agents/experts/knowledge/database-data-management/influxdb-patterns.md +442 -442
- tapps_agents/experts/knowledge/database-data-management/migration-strategies.md +216 -216
- tapps_agents/experts/knowledge/database-data-management/nosql-patterns.md +259 -259
- tapps_agents/experts/knowledge/database-data-management/scalability-patterns.md +184 -184
- tapps_agents/experts/knowledge/database-data-management/sql-optimization.md +175 -175
- tapps_agents/experts/knowledge/database-data-management/time-series-modeling.md +444 -444
- tapps_agents/experts/knowledge/development-workflow/README.md +16 -16
- tapps_agents/experts/knowledge/development-workflow/automation-best-practices.md +216 -216
- tapps_agents/experts/knowledge/development-workflow/build-strategies.md +198 -198
- tapps_agents/experts/knowledge/development-workflow/deployment-patterns.md +205 -205
- tapps_agents/experts/knowledge/development-workflow/git-workflows.md +205 -205
- tapps_agents/experts/knowledge/documentation-knowledge-management/README.md +16 -16
- tapps_agents/experts/knowledge/documentation-knowledge-management/api-documentation-patterns.md +231 -231
- tapps_agents/experts/knowledge/documentation-knowledge-management/documentation-standards.md +191 -191
- tapps_agents/experts/knowledge/documentation-knowledge-management/knowledge-management.md +171 -171
- tapps_agents/experts/knowledge/documentation-knowledge-management/technical-writing-guide.md +192 -192
- tapps_agents/experts/knowledge/observability-monitoring/alerting-patterns.md +461 -461
- tapps_agents/experts/knowledge/observability-monitoring/apm-tools.md +459 -459
- tapps_agents/experts/knowledge/observability-monitoring/distributed-tracing.md +367 -367
- tapps_agents/experts/knowledge/observability-monitoring/logging-strategies.md +478 -478
- tapps_agents/experts/knowledge/observability-monitoring/metrics-and-monitoring.md +510 -510
- tapps_agents/experts/knowledge/observability-monitoring/observability-best-practices.md +492 -492
- tapps_agents/experts/knowledge/observability-monitoring/open-telemetry.md +573 -573
- tapps_agents/experts/knowledge/observability-monitoring/slo-sli-sla.md +419 -419
- tapps_agents/experts/knowledge/performance/anti-patterns.md +284 -284
- tapps_agents/experts/knowledge/performance/api-performance.md +256 -256
- tapps_agents/experts/knowledge/performance/caching.md +327 -327
- tapps_agents/experts/knowledge/performance/database-performance.md +252 -252
- tapps_agents/experts/knowledge/performance/optimization-patterns.md +327 -327
- tapps_agents/experts/knowledge/performance/profiling.md +297 -297
- tapps_agents/experts/knowledge/performance/resource-management.md +293 -293
- tapps_agents/experts/knowledge/performance/scalability.md +306 -306
- tapps_agents/experts/knowledge/security/owasp-top10.md +209 -209
- tapps_agents/experts/knowledge/security/secure-coding-practices.md +207 -207
- tapps_agents/experts/knowledge/security/threat-modeling.md +220 -220
- tapps_agents/experts/knowledge/security/vulnerability-patterns.md +342 -342
- tapps_agents/experts/knowledge/software-architecture/docker-compose-patterns.md +314 -314
- tapps_agents/experts/knowledge/software-architecture/microservices-patterns.md +379 -379
- tapps_agents/experts/knowledge/software-architecture/service-communication.md +316 -316
- tapps_agents/experts/knowledge/testing/best-practices.md +310 -310
- tapps_agents/experts/knowledge/testing/coverage-analysis.md +293 -293
- tapps_agents/experts/knowledge/testing/mocking.md +256 -256
- tapps_agents/experts/knowledge/testing/test-automation.md +276 -276
- tapps_agents/experts/knowledge/testing/test-data.md +271 -271
- tapps_agents/experts/knowledge/testing/test-design-patterns.md +280 -280
- tapps_agents/experts/knowledge/testing/test-maintenance.md +236 -236
- tapps_agents/experts/knowledge/testing/test-strategies.md +311 -311
- tapps_agents/experts/knowledge/user-experience/information-architecture.md +325 -325
- tapps_agents/experts/knowledge/user-experience/interaction-design.md +363 -363
- tapps_agents/experts/knowledge/user-experience/prototyping.md +293 -293
- tapps_agents/experts/knowledge/user-experience/usability-heuristics.md +337 -337
- tapps_agents/experts/knowledge/user-experience/usability-testing.md +311 -311
- tapps_agents/experts/knowledge/user-experience/user-journeys.md +296 -296
- tapps_agents/experts/knowledge/user-experience/user-research.md +373 -373
- tapps_agents/experts/knowledge/user-experience/ux-principles.md +340 -340
- tapps_agents/experts/knowledge_freshness.py +321 -321
- tapps_agents/experts/knowledge_ingestion.py +438 -438
- tapps_agents/experts/knowledge_need_detector.py +93 -93
- tapps_agents/experts/knowledge_validator.py +382 -382
- tapps_agents/experts/observability.py +440 -440
- tapps_agents/experts/passive_notifier.py +238 -238
- tapps_agents/experts/proactive_orchestrator.py +32 -32
- tapps_agents/experts/rag_chunker.py +205 -205
- tapps_agents/experts/rag_embedder.py +152 -152
- tapps_agents/experts/rag_evaluation.py +299 -299
- tapps_agents/experts/rag_index.py +303 -303
- tapps_agents/experts/rag_metrics.py +293 -293
- tapps_agents/experts/rag_safety.py +263 -263
- tapps_agents/experts/report_generator.py +296 -296
- tapps_agents/experts/setup_wizard.py +441 -441
- tapps_agents/experts/simple_rag.py +431 -431
- tapps_agents/experts/vector_rag.py +354 -354
- tapps_agents/experts/weight_distributor.py +304 -304
- tapps_agents/health/__init__.py +24 -24
- tapps_agents/health/base.py +75 -75
- tapps_agents/health/checks/__init__.py +22 -22
- tapps_agents/health/checks/automation.py +127 -127
- tapps_agents/health/checks/context7_cache.py +210 -210
- tapps_agents/health/checks/environment.py +116 -116
- tapps_agents/health/checks/execution.py +170 -170
- tapps_agents/health/checks/knowledge_base.py +187 -187
- tapps_agents/health/checks/outcomes.py +324 -324
- tapps_agents/health/collector.py +280 -280
- tapps_agents/health/dashboard.py +137 -137
- tapps_agents/health/metrics.py +151 -151
- tapps_agents/health/orchestrator.py +271 -271
- tapps_agents/health/registry.py +166 -166
- tapps_agents/hooks/__init__.py +33 -33
- tapps_agents/hooks/config.py +140 -140
- tapps_agents/hooks/events.py +135 -135
- tapps_agents/hooks/executor.py +128 -128
- tapps_agents/hooks/manager.py +143 -143
- tapps_agents/integration/__init__.py +8 -8
- tapps_agents/integration/service_integrator.py +121 -121
- tapps_agents/integrations/__init__.py +10 -10
- tapps_agents/integrations/clawdbot.py +525 -525
- tapps_agents/integrations/memory_bridge.py +356 -356
- tapps_agents/mcp/__init__.py +18 -18
- tapps_agents/mcp/gateway.py +112 -112
- tapps_agents/mcp/servers/__init__.py +13 -13
- tapps_agents/mcp/servers/analysis.py +204 -204
- tapps_agents/mcp/servers/context7.py +198 -198
- tapps_agents/mcp/servers/filesystem.py +218 -218
- tapps_agents/mcp/servers/git.py +201 -201
- tapps_agents/mcp/tool_registry.py +115 -115
- tapps_agents/quality/__init__.py +54 -54
- tapps_agents/quality/coverage_analyzer.py +379 -379
- tapps_agents/quality/enforcement.py +82 -82
- tapps_agents/quality/gates/__init__.py +37 -37
- tapps_agents/quality/gates/approval_gate.py +255 -255
- tapps_agents/quality/gates/base.py +84 -84
- tapps_agents/quality/gates/exceptions.py +43 -43
- tapps_agents/quality/gates/policy_gate.py +195 -195
- tapps_agents/quality/gates/registry.py +239 -239
- tapps_agents/quality/gates/security_gate.py +156 -156
- tapps_agents/quality/quality_gates.py +369 -369
- tapps_agents/quality/secret_scanner.py +335 -335
- tapps_agents/session/__init__.py +19 -19
- tapps_agents/session/manager.py +256 -256
- tapps_agents/simple_mode/__init__.py +66 -66
- tapps_agents/simple_mode/agent_contracts.py +357 -357
- tapps_agents/simple_mode/beads_hooks.py +151 -151
- tapps_agents/simple_mode/code_snippet_handler.py +382 -382
- tapps_agents/simple_mode/documentation_manager.py +395 -395
- tapps_agents/simple_mode/documentation_reader.py +187 -187
- tapps_agents/simple_mode/file_inference.py +292 -292
- tapps_agents/simple_mode/framework_change_detector.py +268 -268
- tapps_agents/simple_mode/intent_parser.py +510 -510
- tapps_agents/simple_mode/learning_progression.py +358 -358
- tapps_agents/simple_mode/nl_handler.py +700 -700
- tapps_agents/simple_mode/onboarding.py +253 -253
- tapps_agents/simple_mode/orchestrators/__init__.py +38 -38
- tapps_agents/simple_mode/orchestrators/base.py +185 -185
- tapps_agents/simple_mode/orchestrators/breakdown_orchestrator.py +49 -49
- tapps_agents/simple_mode/orchestrators/brownfield_orchestrator.py +135 -135
- tapps_agents/simple_mode/orchestrators/build_orchestrator.py +2700 -2667
- tapps_agents/simple_mode/orchestrators/deliverable_checklist.py +349 -349
- tapps_agents/simple_mode/orchestrators/enhance_orchestrator.py +53 -53
- tapps_agents/simple_mode/orchestrators/epic_orchestrator.py +122 -122
- tapps_agents/simple_mode/orchestrators/explore_orchestrator.py +184 -184
- tapps_agents/simple_mode/orchestrators/fix_orchestrator.py +723 -723
- tapps_agents/simple_mode/orchestrators/plan_analysis_orchestrator.py +206 -206
- tapps_agents/simple_mode/orchestrators/pr_orchestrator.py +237 -237
- tapps_agents/simple_mode/orchestrators/refactor_orchestrator.py +222 -222
- tapps_agents/simple_mode/orchestrators/requirements_tracer.py +262 -262
- tapps_agents/simple_mode/orchestrators/resume_orchestrator.py +210 -210
- tapps_agents/simple_mode/orchestrators/review_orchestrator.py +161 -161
- tapps_agents/simple_mode/orchestrators/test_orchestrator.py +82 -82
- tapps_agents/simple_mode/output_aggregator.py +340 -340
- tapps_agents/simple_mode/result_formatters.py +598 -598
- tapps_agents/simple_mode/step_dependencies.py +382 -382
- tapps_agents/simple_mode/step_results.py +276 -276
- tapps_agents/simple_mode/streaming.py +388 -388
- tapps_agents/simple_mode/variations.py +129 -129
- tapps_agents/simple_mode/visual_feedback.py +238 -238
- tapps_agents/simple_mode/zero_config.py +274 -274
- tapps_agents/suggestions/__init__.py +8 -8
- tapps_agents/suggestions/inline_suggester.py +52 -52
- tapps_agents/templates/__init__.py +8 -8
- tapps_agents/templates/microservice_generator.py +274 -274
- tapps_agents/utils/env_validator.py +291 -291
- tapps_agents/workflow/__init__.py +171 -171
- tapps_agents/workflow/acceptance_verifier.py +132 -132
- tapps_agents/workflow/agent_handlers/__init__.py +41 -41
- tapps_agents/workflow/agent_handlers/analyst_handler.py +75 -75
- tapps_agents/workflow/agent_handlers/architect_handler.py +107 -107
- tapps_agents/workflow/agent_handlers/base.py +84 -84
- tapps_agents/workflow/agent_handlers/debugger_handler.py +100 -100
- tapps_agents/workflow/agent_handlers/designer_handler.py +110 -110
- tapps_agents/workflow/agent_handlers/documenter_handler.py +94 -94
- tapps_agents/workflow/agent_handlers/implementer_handler.py +235 -235
- tapps_agents/workflow/agent_handlers/ops_handler.py +62 -62
- tapps_agents/workflow/agent_handlers/orchestrator_handler.py +43 -43
- tapps_agents/workflow/agent_handlers/planner_handler.py +98 -98
- tapps_agents/workflow/agent_handlers/registry.py +119 -119
- tapps_agents/workflow/agent_handlers/reviewer_handler.py +119 -119
- tapps_agents/workflow/agent_handlers/tester_handler.py +69 -69
- tapps_agents/workflow/analytics_accessor.py +337 -337
- tapps_agents/workflow/analytics_alerts.py +416 -416
- tapps_agents/workflow/analytics_dashboard_cursor.py +281 -281
- tapps_agents/workflow/analytics_dual_write.py +103 -103
- tapps_agents/workflow/analytics_integration.py +119 -119
- tapps_agents/workflow/analytics_query_parser.py +278 -278
- tapps_agents/workflow/analytics_visualizer.py +259 -259
- tapps_agents/workflow/artifact_helper.py +204 -204
- tapps_agents/workflow/audit_logger.py +263 -263
- tapps_agents/workflow/auto_execution_config.py +340 -340
- tapps_agents/workflow/auto_progression.py +586 -586
- tapps_agents/workflow/branch_cleanup.py +349 -349
- tapps_agents/workflow/checkpoint.py +256 -256
- tapps_agents/workflow/checkpoint_manager.py +178 -178
- tapps_agents/workflow/code_artifact.py +179 -179
- tapps_agents/workflow/common_enums.py +96 -96
- tapps_agents/workflow/confirmation_handler.py +130 -130
- tapps_agents/workflow/context_analyzer.py +222 -222
- tapps_agents/workflow/context_artifact.py +230 -230
- tapps_agents/workflow/cursor_chat.py +94 -94
- tapps_agents/workflow/cursor_executor.py +2337 -2196
- tapps_agents/workflow/cursor_skill_helper.py +516 -516
- tapps_agents/workflow/dependency_resolver.py +244 -244
- tapps_agents/workflow/design_artifact.py +156 -156
- tapps_agents/workflow/detector.py +751 -751
- tapps_agents/workflow/direct_execution_fallback.py +301 -301
- tapps_agents/workflow/docs_artifact.py +168 -168
- tapps_agents/workflow/enforcer.py +389 -389
- tapps_agents/workflow/enhancement_artifact.py +142 -142
- tapps_agents/workflow/error_recovery.py +806 -806
- tapps_agents/workflow/event_bus.py +183 -183
- tapps_agents/workflow/event_log.py +612 -612
- tapps_agents/workflow/events.py +63 -63
- tapps_agents/workflow/exceptions.py +43 -43
- tapps_agents/workflow/execution_graph.py +498 -498
- tapps_agents/workflow/execution_plan.py +126 -126
- tapps_agents/workflow/file_utils.py +186 -186
- tapps_agents/workflow/gate_evaluator.py +182 -182
- tapps_agents/workflow/gate_integration.py +200 -200
- tapps_agents/workflow/graph_visualizer.py +130 -130
- tapps_agents/workflow/health_checker.py +206 -206
- tapps_agents/workflow/logging_helper.py +243 -243
- tapps_agents/workflow/manifest.py +582 -582
- tapps_agents/workflow/marker_writer.py +250 -250
- tapps_agents/workflow/message_formatter.py +188 -188
- tapps_agents/workflow/messaging.py +325 -325
- tapps_agents/workflow/metadata_models.py +91 -91
- tapps_agents/workflow/metrics_integration.py +226 -226
- tapps_agents/workflow/migration_utils.py +116 -116
- tapps_agents/workflow/models.py +148 -111
- tapps_agents/workflow/nlp_config.py +198 -198
- tapps_agents/workflow/nlp_error_handler.py +207 -207
- tapps_agents/workflow/nlp_executor.py +163 -163
- tapps_agents/workflow/nlp_parser.py +528 -528
- tapps_agents/workflow/observability_dashboard.py +451 -451
- tapps_agents/workflow/observer.py +170 -170
- tapps_agents/workflow/ops_artifact.py +257 -257
- tapps_agents/workflow/output_passing.py +214 -214
- tapps_agents/workflow/parallel_executor.py +463 -463
- tapps_agents/workflow/planning_artifact.py +179 -179
- tapps_agents/workflow/preset_loader.py +285 -285
- tapps_agents/workflow/preset_recommender.py +270 -270
- tapps_agents/workflow/progress_logger.py +145 -145
- tapps_agents/workflow/progress_manager.py +303 -303
- tapps_agents/workflow/progress_monitor.py +186 -186
- tapps_agents/workflow/progress_updates.py +423 -423
- tapps_agents/workflow/quality_artifact.py +158 -158
- tapps_agents/workflow/quality_loopback.py +101 -101
- tapps_agents/workflow/recommender.py +387 -387
- tapps_agents/workflow/remediation_loop.py +166 -166
- tapps_agents/workflow/result_aggregator.py +300 -300
- tapps_agents/workflow/review_artifact.py +185 -185
- tapps_agents/workflow/schema_validator.py +522 -522
- tapps_agents/workflow/session_handoff.py +178 -178
- tapps_agents/workflow/skill_invoker.py +648 -648
- tapps_agents/workflow/state_manager.py +756 -756
- tapps_agents/workflow/state_persistence_config.py +331 -331
- tapps_agents/workflow/status_monitor.py +449 -449
- tapps_agents/workflow/step_checkpoint.py +314 -314
- tapps_agents/workflow/step_details.py +201 -201
- tapps_agents/workflow/story_models.py +147 -147
- tapps_agents/workflow/streaming.py +416 -416
- tapps_agents/workflow/suggestion_engine.py +552 -552
- tapps_agents/workflow/testing_artifact.py +186 -186
- tapps_agents/workflow/timeline.py +158 -158
- tapps_agents/workflow/token_integration.py +209 -209
- tapps_agents/workflow/validation.py +217 -217
- tapps_agents/workflow/visual_feedback.py +391 -391
- tapps_agents/workflow/workflow_chain.py +95 -95
- tapps_agents/workflow/workflow_summary.py +219 -219
- tapps_agents/workflow/worktree_manager.py +724 -724
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/METADATA +672 -672
- tapps_agents-3.6.0.dist-info/RECORD +758 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/licenses/LICENSE +22 -22
- tapps_agents/health/checks/outcomes.backup_20260204_064058.py +0 -324
- tapps_agents/health/checks/outcomes.backup_20260204_064256.py +0 -324
- tapps_agents/health/checks/outcomes.backup_20260204_064600.py +0 -324
- tapps_agents-3.5.40.dist-info/RECORD +0 -760
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/WHEEL +0 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/top_level.txt +0 -0
|
@@ -1,507 +1,507 @@
|
|
|
1
|
-
# Rate Limiting Patterns
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Rate limiting protects APIs from abuse and ensures fair resource usage. It controls the number of requests a client can make within a specific time window.
|
|
6
|
-
|
|
7
|
-
## Rate Limiting Algorithms
|
|
8
|
-
|
|
9
|
-
### 1. Fixed Window
|
|
10
|
-
|
|
11
|
-
**Concept:** Requests allowed per fixed time window
|
|
12
|
-
|
|
13
|
-
**Example:** 100 requests per minute
|
|
14
|
-
|
|
15
|
-
**Pros:**
|
|
16
|
-
- Simple to implement
|
|
17
|
-
- Memory efficient
|
|
18
|
-
- Predictable
|
|
19
|
-
|
|
20
|
-
**Cons:**
|
|
21
|
-
- Burst at window boundaries
|
|
22
|
-
- Uneven distribution
|
|
23
|
-
|
|
24
|
-
**Implementation:**
|
|
25
|
-
```python
|
|
26
|
-
from collections import defaultdict
|
|
27
|
-
from datetime import datetime, timedelta
|
|
28
|
-
|
|
29
|
-
class FixedWindowRateLimiter:
|
|
30
|
-
def __init__(self, max_requests, window_seconds):
|
|
31
|
-
self.max_requests = max_requests
|
|
32
|
-
self.window_seconds = window_seconds
|
|
33
|
-
self.windows = defaultdict(int)
|
|
34
|
-
self.window_starts = {}
|
|
35
|
-
|
|
36
|
-
def is_allowed(self, key):
|
|
37
|
-
now = datetime.now()
|
|
38
|
-
window_start = now.replace(second=0, microsecond=0)
|
|
39
|
-
|
|
40
|
-
if key not in self.window_starts or \
|
|
41
|
-
window_start > self.window_starts[key] + timedelta(seconds=self.window_seconds):
|
|
42
|
-
# New window
|
|
43
|
-
self.windows[key] = 0
|
|
44
|
-
self.window_starts[key] = window_start
|
|
45
|
-
|
|
46
|
-
if self.windows[key] >= self.max_requests:
|
|
47
|
-
return False
|
|
48
|
-
|
|
49
|
-
self.windows[key] += 1
|
|
50
|
-
return True
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 2. Sliding Window
|
|
54
|
-
|
|
55
|
-
**Concept:** Track requests in rolling time window
|
|
56
|
-
|
|
57
|
-
**Example:** 100 requests in any 60-second window
|
|
58
|
-
|
|
59
|
-
**Pros:**
|
|
60
|
-
- More accurate
|
|
61
|
-
- Smoother distribution
|
|
62
|
-
- Prevents bursts
|
|
63
|
-
|
|
64
|
-
**Cons:**
|
|
65
|
-
- More memory
|
|
66
|
-
- More complex
|
|
67
|
-
|
|
68
|
-
**Implementation:**
|
|
69
|
-
```python
|
|
70
|
-
from collections import deque
|
|
71
|
-
from datetime import datetime, timedelta
|
|
72
|
-
|
|
73
|
-
class SlidingWindowRateLimiter:
|
|
74
|
-
def __init__(self, max_requests, window_seconds):
|
|
75
|
-
self.max_requests = max_requests
|
|
76
|
-
self.window_seconds = window_seconds
|
|
77
|
-
self.requests = defaultdict(deque)
|
|
78
|
-
|
|
79
|
-
def is_allowed(self, key):
|
|
80
|
-
now = datetime.now()
|
|
81
|
-
cutoff = now - timedelta(seconds=self.window_seconds)
|
|
82
|
-
|
|
83
|
-
# Remove old requests
|
|
84
|
-
while self.requests[key] and self.requests[key][0] < cutoff:
|
|
85
|
-
self.requests[key].popleft()
|
|
86
|
-
|
|
87
|
-
if len(self.requests[key]) >= self.max_requests:
|
|
88
|
-
return False
|
|
89
|
-
|
|
90
|
-
self.requests[key].append(now)
|
|
91
|
-
return True
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### 3. Token Bucket
|
|
95
|
-
|
|
96
|
-
**Concept:** Tokens added at fixed rate, consumed per request
|
|
97
|
-
|
|
98
|
-
**Example:** 10 tokens/sec, max 100 tokens
|
|
99
|
-
|
|
100
|
-
**Pros:**
|
|
101
|
-
- Allows bursts
|
|
102
|
-
- Smooths traffic
|
|
103
|
-
- Flexible
|
|
104
|
-
|
|
105
|
-
**Cons:**
|
|
106
|
-
- More complex
|
|
107
|
-
- State management
|
|
108
|
-
|
|
109
|
-
**Implementation:**
|
|
110
|
-
```python
|
|
111
|
-
from datetime import datetime, timedelta
|
|
112
|
-
|
|
113
|
-
class TokenBucketRateLimiter:
|
|
114
|
-
def __init__(self, capacity, refill_rate):
|
|
115
|
-
self.capacity = capacity
|
|
116
|
-
self.refill_rate = refill_rate # tokens per second
|
|
117
|
-
self.tokens = defaultdict(lambda: capacity)
|
|
118
|
-
self.last_refill = defaultdict(datetime.now)
|
|
119
|
-
|
|
120
|
-
def is_allowed(self, key):
|
|
121
|
-
now = datetime.now()
|
|
122
|
-
elapsed = (now - self.last_refill[key]).total_seconds()
|
|
123
|
-
|
|
124
|
-
# Refill tokens
|
|
125
|
-
self.tokens[key] = min(
|
|
126
|
-
self.capacity,
|
|
127
|
-
self.tokens[key] + elapsed * self.refill_rate
|
|
128
|
-
)
|
|
129
|
-
self.last_refill[key] = now
|
|
130
|
-
|
|
131
|
-
if self.tokens[key] >= 1:
|
|
132
|
-
self.tokens[key] -= 1
|
|
133
|
-
return True
|
|
134
|
-
return False
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 4. Leaky Bucket
|
|
138
|
-
|
|
139
|
-
**Concept:** Requests leak out at constant rate
|
|
140
|
-
|
|
141
|
-
**Example:** Process 10 requests/sec, queue up to 100
|
|
142
|
-
|
|
143
|
-
**Pros:**
|
|
144
|
-
- Smooths output
|
|
145
|
-
- Handles bursts
|
|
146
|
-
- Predictable rate
|
|
147
|
-
|
|
148
|
-
**Cons:**
|
|
149
|
-
- Queue management
|
|
150
|
-
- Memory usage
|
|
151
|
-
|
|
152
|
-
## Implementation Patterns
|
|
153
|
-
|
|
154
|
-
### Redis-Based Rate Limiting
|
|
155
|
-
|
|
156
|
-
**Using Fixed Window:**
|
|
157
|
-
```python
|
|
158
|
-
import redis
|
|
159
|
-
from datetime import datetime
|
|
160
|
-
|
|
161
|
-
redis_client = redis.Redis()
|
|
162
|
-
|
|
163
|
-
def rate_limit(key, max_requests, window_seconds):
|
|
164
|
-
now = datetime.now()
|
|
165
|
-
window = int(now.timestamp() / window_seconds)
|
|
166
|
-
redis_key = f"ratelimit:{key}:{window}"
|
|
167
|
-
|
|
168
|
-
current = redis_client.incr(redis_key)
|
|
169
|
-
if current == 1:
|
|
170
|
-
redis_client.expire(redis_key, window_seconds)
|
|
171
|
-
|
|
172
|
-
return current <= max_requests
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
**Using Sliding Window with Sorted Sets:**
|
|
176
|
-
```python
|
|
177
|
-
def sliding_window_rate_limit(key, max_requests, window_seconds):
|
|
178
|
-
now = datetime.now().timestamp()
|
|
179
|
-
cutoff = now - window_seconds
|
|
180
|
-
|
|
181
|
-
redis_key = f"ratelimit:{key}"
|
|
182
|
-
|
|
183
|
-
# Remove old entries
|
|
184
|
-
redis_client.zremrangebyscore(redis_key, 0, cutoff)
|
|
185
|
-
|
|
186
|
-
# Count current requests
|
|
187
|
-
current = redis_client.zcard(redis_key)
|
|
188
|
-
|
|
189
|
-
if current < max_requests:
|
|
190
|
-
redis_client.zadd(redis_key, {str(now): now})
|
|
191
|
-
redis_client.expire(redis_key, window_seconds)
|
|
192
|
-
return True
|
|
193
|
-
|
|
194
|
-
return False
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Middleware Pattern
|
|
198
|
-
|
|
199
|
-
**Flask Example:**
|
|
200
|
-
```python
|
|
201
|
-
from flask import request, g, jsonify
|
|
202
|
-
from functools import wraps
|
|
203
|
-
|
|
204
|
-
def rate_limit(max_requests, window_seconds):
|
|
205
|
-
def decorator(f):
|
|
206
|
-
@wraps(f)
|
|
207
|
-
def decorated_function(*args, **kwargs):
|
|
208
|
-
key = get_rate_limit_key() # IP, user ID, API key
|
|
209
|
-
|
|
210
|
-
if not rate_limiter.is_allowed(key, max_requests, window_seconds):
|
|
211
|
-
return jsonify({
|
|
212
|
-
"error": "Rate limit exceeded"
|
|
213
|
-
}), 429
|
|
214
|
-
|
|
215
|
-
return f(*args, **kwargs)
|
|
216
|
-
return decorated_function
|
|
217
|
-
return decorator
|
|
218
|
-
|
|
219
|
-
@app.route('/api/users')
|
|
220
|
-
@rate_limit(max_requests=100, window_seconds=60)
|
|
221
|
-
def get_users():
|
|
222
|
-
return jsonify(users=[...])
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Header Response
|
|
226
|
-
|
|
227
|
-
**Rate Limit Headers:**
|
|
228
|
-
```python
|
|
229
|
-
def add_rate_limit_headers(response, remaining, reset_time):
|
|
230
|
-
response.headers['X-RateLimit-Limit'] = str(max_requests)
|
|
231
|
-
response.headers['X-RateLimit-Remaining'] = str(remaining)
|
|
232
|
-
response.headers['X-RateLimit-Reset'] = str(int(reset_time.timestamp()))
|
|
233
|
-
return response
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
**RFC 6585 Standard Headers:**
|
|
237
|
-
```http
|
|
238
|
-
HTTP/1.1 429 Too Many Requests
|
|
239
|
-
Retry-After: 60
|
|
240
|
-
X-RateLimit-Limit: 100
|
|
241
|
-
X-RateLimit-Remaining: 0
|
|
242
|
-
X-RateLimit-Reset: 1642233600
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Rate Limit Keys
|
|
246
|
-
|
|
247
|
-
### By IP Address
|
|
248
|
-
|
|
249
|
-
**Simple but Limited:**
|
|
250
|
-
```python
|
|
251
|
-
def get_rate_limit_key():
|
|
252
|
-
return request.remote_addr
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### By API Key
|
|
256
|
-
|
|
257
|
-
**Better for APIs:**
|
|
258
|
-
```python
|
|
259
|
-
def get_rate_limit_key():
|
|
260
|
-
api_key = request.headers.get('X-API-Key')
|
|
261
|
-
return f"apikey:{api_key}"
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### By User ID
|
|
265
|
-
|
|
266
|
-
**For Authenticated Users:**
|
|
267
|
-
```python
|
|
268
|
-
def get_rate_limit_key():
|
|
269
|
-
user_id = g.current_user.id
|
|
270
|
-
return f"user:{user_id}"
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Composite Keys
|
|
274
|
-
|
|
275
|
-
**Multiple Factors:**
|
|
276
|
-
```python
|
|
277
|
-
def get_rate_limit_key():
|
|
278
|
-
user_id = g.current_user.id if g.current_user else None
|
|
279
|
-
endpoint = request.endpoint
|
|
280
|
-
return f"{user_id}:{endpoint}"
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
## Tiered Rate Limits
|
|
284
|
-
|
|
285
|
-
### Different Limits per Tier
|
|
286
|
-
|
|
287
|
-
**Free Tier:**
|
|
288
|
-
```python
|
|
289
|
-
FREE_TIER_LIMITS = {
|
|
290
|
-
'requests_per_minute': 60,
|
|
291
|
-
'requests_per_hour': 1000,
|
|
292
|
-
'requests_per_day': 10000
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
**Premium Tier:**
|
|
297
|
-
```python
|
|
298
|
-
PREMIUM_TIER_LIMITS = {
|
|
299
|
-
'requests_per_minute': 600,
|
|
300
|
-
'requests_per_hour': 100000,
|
|
301
|
-
'requests_per_day': 1000000
|
|
302
|
-
}
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
**Implementation:**
|
|
306
|
-
```python
|
|
307
|
-
def get_rate_limits(user_tier):
|
|
308
|
-
limits = {
|
|
309
|
-
'free': FREE_TIER_LIMITS,
|
|
310
|
-
'premium': PREMIUM_TIER_LIMITS
|
|
311
|
-
}.get(user_tier, FREE_TIER_LIMITS)
|
|
312
|
-
|
|
313
|
-
return limits
|
|
314
|
-
|
|
315
|
-
def check_rate_limit(user, endpoint):
|
|
316
|
-
limits = get_rate_limits(user.tier)
|
|
317
|
-
|
|
318
|
-
for window, max_requests in limits.items():
|
|
319
|
-
if not rate_limiter.is_allowed(
|
|
320
|
-
f"{user.id}:{endpoint}",
|
|
321
|
-
max_requests,
|
|
322
|
-
parse_window(window)
|
|
323
|
-
):
|
|
324
|
-
return False
|
|
325
|
-
return True
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
## Error Responses
|
|
329
|
-
|
|
330
|
-
### Standard 429 Response
|
|
331
|
-
|
|
332
|
-
**Format:**
|
|
333
|
-
```json
|
|
334
|
-
{
|
|
335
|
-
"error": {
|
|
336
|
-
"code": "RATE_LIMIT_EXCEEDED",
|
|
337
|
-
"message": "Rate limit exceeded. Try again in 60 seconds.",
|
|
338
|
-
"retry_after": 60
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
**Implementation:**
|
|
344
|
-
```python
|
|
345
|
-
@app.errorhandler(429)
|
|
346
|
-
def rate_limit_exceeded(error):
|
|
347
|
-
return jsonify({
|
|
348
|
-
"error": {
|
|
349
|
-
"code": "RATE_LIMIT_EXCEEDED",
|
|
350
|
-
"message": "Rate limit exceeded",
|
|
351
|
-
"retry_after": error.retry_after
|
|
352
|
-
}
|
|
353
|
-
}), 429
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
## Best Practices
|
|
357
|
-
|
|
358
|
-
1. **Choose appropriate algorithm:** Sliding window for accuracy
|
|
359
|
-
2. **Use Redis for distributed:** Shared state across instances
|
|
360
|
-
3. **Set reasonable limits:** Balance protection and usability
|
|
361
|
-
4. **Include rate limit headers:** Inform clients of limits
|
|
362
|
-
5. **Return 429 status:** Standard HTTP status for rate limits
|
|
363
|
-
6. **Include Retry-After:** Tell clients when to retry
|
|
364
|
-
7. **Log rate limit hits:** Monitor for abuse patterns
|
|
365
|
-
8. **Tier limits appropriately:** Different limits per user tier
|
|
366
|
-
9. **Whitelist if needed:** Exempt certain keys/IPs
|
|
367
|
-
10. **Test thoroughly:** Ensure limits work as expected
|
|
368
|
-
|
|
369
|
-
## Common Patterns
|
|
370
|
-
|
|
371
|
-
### Per-Endpoint Limits
|
|
372
|
-
|
|
373
|
-
```python
|
|
374
|
-
ENDPOINT_LIMITS = {
|
|
375
|
-
'/api/users': {'max': 100, 'window': 60},
|
|
376
|
-
'/api/orders': {'max': 50, 'window': 60},
|
|
377
|
-
'/api/reports': {'max': 10, 'window': 300},
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### Burst Protection
|
|
382
|
-
|
|
383
|
-
```python
|
|
384
|
-
# Allow bursts but limit sustained rate
|
|
385
|
-
BURST_LIMIT = 20 # Immediate burst
|
|
386
|
-
SUSTAINED_LIMIT = 100 # Per minute
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
### Adaptive Rate Limiting
|
|
390
|
-
|
|
391
|
-
```python
|
|
392
|
-
def adaptive_rate_limit(user):
|
|
393
|
-
# Increase limit for good users
|
|
394
|
-
if user.reputation_score > 0.95:
|
|
395
|
-
return PREMIUM_LIMITS
|
|
396
|
-
elif user.reputation_score > 0.8:
|
|
397
|
-
return STANDARD_LIMITS
|
|
398
|
-
else:
|
|
399
|
-
return REDUCED_LIMITS
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
## External API Rate Limiting
|
|
403
|
-
|
|
404
|
-
### Pattern 1: Client-Side Rate Limiting
|
|
405
|
-
|
|
406
|
-
**Respect External API Limits:**
|
|
407
|
-
```python
|
|
408
|
-
from collections import deque
|
|
409
|
-
from datetime import datetime, timedelta
|
|
410
|
-
|
|
411
|
-
class ExternalAPIRateLimiter:
|
|
412
|
-
def __init__(self, max_requests: int, time_window: int):
|
|
413
|
-
self.max_requests = max_requests
|
|
414
|
-
self.time_window = timedelta(seconds=time_window)
|
|
415
|
-
self.requests = deque()
|
|
416
|
-
|
|
417
|
-
async def acquire(self):
|
|
418
|
-
"""Acquire rate limit token."""
|
|
419
|
-
now = datetime.now()
|
|
420
|
-
|
|
421
|
-
# Remove old requests
|
|
422
|
-
while self.requests and now - self.requests[0] > self.time_window:
|
|
423
|
-
self.requests.popleft()
|
|
424
|
-
|
|
425
|
-
# Check if limit reached
|
|
426
|
-
if len(self.requests) >= self.max_requests:
|
|
427
|
-
wait_time = (self.requests[0] + self.time_window - now).total_seconds()
|
|
428
|
-
await asyncio.sleep(wait_time)
|
|
429
|
-
return await self.acquire()
|
|
430
|
-
|
|
431
|
-
# Add current request
|
|
432
|
-
self.requests.append(now)
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Pattern 2: API-Specific Rate Limits
|
|
436
|
-
|
|
437
|
-
**Different Limits per API:**
|
|
438
|
-
```python
|
|
439
|
-
class APIRateLimitManager:
|
|
440
|
-
def __init__(self):
|
|
441
|
-
self.limiters = {
|
|
442
|
-
"openweathermap": ExternalAPIRateLimiter(max_requests=60, time_window=60),
|
|
443
|
-
"watttime": ExternalAPIRateLimiter(max_requests=100, time_window=60),
|
|
444
|
-
"airnow": ExternalAPIRateLimiter(max_requests=500, time_window=3600),
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
async def acquire(self, api_name: str):
|
|
448
|
-
"""Acquire rate limit for specific API."""
|
|
449
|
-
if api_name in self.limiters:
|
|
450
|
-
await self.limiters[api_name].acquire()
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
### Pattern 3: Retry with Rate Limit Awareness
|
|
454
|
-
|
|
455
|
-
**Handle 429 Responses:**
|
|
456
|
-
```python
|
|
457
|
-
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
|
|
458
|
-
|
|
459
|
-
class RateLimitAwareClient:
|
|
460
|
-
def __init__(self, base_url: str, api_key: str):
|
|
461
|
-
self.base_url = base_url
|
|
462
|
-
self.api_key = api_key
|
|
463
|
-
self.client = httpx.AsyncClient()
|
|
464
|
-
self.rate_limit = ExternalAPIRateLimiter(max_requests=60, time_window=60)
|
|
465
|
-
|
|
466
|
-
@retry(
|
|
467
|
-
stop=stop_after_attempt(3),
|
|
468
|
-
wait=wait_exponential(multiplier=1, min=2, max=10),
|
|
469
|
-
retry=retry_if_exception_type(httpx.HTTPStatusError)
|
|
470
|
-
)
|
|
471
|
-
async def get(self, endpoint: str):
|
|
472
|
-
"""GET request with rate limit awareness."""
|
|
473
|
-
await self.rate_limit.acquire()
|
|
474
|
-
|
|
475
|
-
response = await self.client.get(
|
|
476
|
-
f"{self.base_url}/{endpoint}",
|
|
477
|
-
headers={"Authorization": f"Bearer {self.api_key}"}
|
|
478
|
-
)
|
|
479
|
-
|
|
480
|
-
# Handle 429 (Too Many Requests)
|
|
481
|
-
if response.status_code == 429:
|
|
482
|
-
retry_after = int(response.headers.get("Retry-After", 60))
|
|
483
|
-
await asyncio.sleep(retry_after)
|
|
484
|
-
raise httpx.HTTPStatusError("Rate limit exceeded", request=response.request, response=response)
|
|
485
|
-
|
|
486
|
-
response.raise_for_status()
|
|
487
|
-
return response.json()
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
**See Also:**
|
|
491
|
-
- `external-api-integration.md` - Comprehensive external API integration patterns
|
|
492
|
-
|
|
493
|
-
## Tools
|
|
494
|
-
|
|
495
|
-
### Open Source
|
|
496
|
-
|
|
497
|
-
- **Redis:** Distributed rate limiting
|
|
498
|
-
- **nginx rate limiting:** Built-in module
|
|
499
|
-
- **Kong:** API gateway with rate limiting
|
|
500
|
-
- **Envoy:** Service mesh with rate limiting
|
|
501
|
-
|
|
502
|
-
### Commercial
|
|
503
|
-
|
|
504
|
-
- **CloudFlare:** DDoS protection and rate limiting
|
|
505
|
-
- **AWS API Gateway:** Built-in throttling
|
|
506
|
-
- **Azure API Management:** Rate limit policies
|
|
507
|
-
|
|
1
|
+
# Rate Limiting Patterns
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Rate limiting protects APIs from abuse and ensures fair resource usage. It controls the number of requests a client can make within a specific time window.
|
|
6
|
+
|
|
7
|
+
## Rate Limiting Algorithms
|
|
8
|
+
|
|
9
|
+
### 1. Fixed Window
|
|
10
|
+
|
|
11
|
+
**Concept:** Requests allowed per fixed time window
|
|
12
|
+
|
|
13
|
+
**Example:** 100 requests per minute
|
|
14
|
+
|
|
15
|
+
**Pros:**
|
|
16
|
+
- Simple to implement
|
|
17
|
+
- Memory efficient
|
|
18
|
+
- Predictable
|
|
19
|
+
|
|
20
|
+
**Cons:**
|
|
21
|
+
- Burst at window boundaries
|
|
22
|
+
- Uneven distribution
|
|
23
|
+
|
|
24
|
+
**Implementation:**
|
|
25
|
+
```python
|
|
26
|
+
from collections import defaultdict
|
|
27
|
+
from datetime import datetime, timedelta
|
|
28
|
+
|
|
29
|
+
class FixedWindowRateLimiter:
|
|
30
|
+
def __init__(self, max_requests, window_seconds):
|
|
31
|
+
self.max_requests = max_requests
|
|
32
|
+
self.window_seconds = window_seconds
|
|
33
|
+
self.windows = defaultdict(int)
|
|
34
|
+
self.window_starts = {}
|
|
35
|
+
|
|
36
|
+
def is_allowed(self, key):
|
|
37
|
+
now = datetime.now()
|
|
38
|
+
window_start = now.replace(second=0, microsecond=0)
|
|
39
|
+
|
|
40
|
+
if key not in self.window_starts or \
|
|
41
|
+
window_start > self.window_starts[key] + timedelta(seconds=self.window_seconds):
|
|
42
|
+
# New window
|
|
43
|
+
self.windows[key] = 0
|
|
44
|
+
self.window_starts[key] = window_start
|
|
45
|
+
|
|
46
|
+
if self.windows[key] >= self.max_requests:
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
self.windows[key] += 1
|
|
50
|
+
return True
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Sliding Window
|
|
54
|
+
|
|
55
|
+
**Concept:** Track requests in rolling time window
|
|
56
|
+
|
|
57
|
+
**Example:** 100 requests in any 60-second window
|
|
58
|
+
|
|
59
|
+
**Pros:**
|
|
60
|
+
- More accurate
|
|
61
|
+
- Smoother distribution
|
|
62
|
+
- Prevents bursts
|
|
63
|
+
|
|
64
|
+
**Cons:**
|
|
65
|
+
- More memory
|
|
66
|
+
- More complex
|
|
67
|
+
|
|
68
|
+
**Implementation:**
|
|
69
|
+
```python
|
|
70
|
+
from collections import deque
|
|
71
|
+
from datetime import datetime, timedelta
|
|
72
|
+
|
|
73
|
+
class SlidingWindowRateLimiter:
|
|
74
|
+
def __init__(self, max_requests, window_seconds):
|
|
75
|
+
self.max_requests = max_requests
|
|
76
|
+
self.window_seconds = window_seconds
|
|
77
|
+
self.requests = defaultdict(deque)
|
|
78
|
+
|
|
79
|
+
def is_allowed(self, key):
|
|
80
|
+
now = datetime.now()
|
|
81
|
+
cutoff = now - timedelta(seconds=self.window_seconds)
|
|
82
|
+
|
|
83
|
+
# Remove old requests
|
|
84
|
+
while self.requests[key] and self.requests[key][0] < cutoff:
|
|
85
|
+
self.requests[key].popleft()
|
|
86
|
+
|
|
87
|
+
if len(self.requests[key]) >= self.max_requests:
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
self.requests[key].append(now)
|
|
91
|
+
return True
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Token Bucket
|
|
95
|
+
|
|
96
|
+
**Concept:** Tokens added at fixed rate, consumed per request
|
|
97
|
+
|
|
98
|
+
**Example:** 10 tokens/sec, max 100 tokens
|
|
99
|
+
|
|
100
|
+
**Pros:**
|
|
101
|
+
- Allows bursts
|
|
102
|
+
- Smooths traffic
|
|
103
|
+
- Flexible
|
|
104
|
+
|
|
105
|
+
**Cons:**
|
|
106
|
+
- More complex
|
|
107
|
+
- State management
|
|
108
|
+
|
|
109
|
+
**Implementation:**
|
|
110
|
+
```python
|
|
111
|
+
from datetime import datetime, timedelta
|
|
112
|
+
|
|
113
|
+
class TokenBucketRateLimiter:
|
|
114
|
+
def __init__(self, capacity, refill_rate):
|
|
115
|
+
self.capacity = capacity
|
|
116
|
+
self.refill_rate = refill_rate # tokens per second
|
|
117
|
+
self.tokens = defaultdict(lambda: capacity)
|
|
118
|
+
self.last_refill = defaultdict(datetime.now)
|
|
119
|
+
|
|
120
|
+
def is_allowed(self, key):
|
|
121
|
+
now = datetime.now()
|
|
122
|
+
elapsed = (now - self.last_refill[key]).total_seconds()
|
|
123
|
+
|
|
124
|
+
# Refill tokens
|
|
125
|
+
self.tokens[key] = min(
|
|
126
|
+
self.capacity,
|
|
127
|
+
self.tokens[key] + elapsed * self.refill_rate
|
|
128
|
+
)
|
|
129
|
+
self.last_refill[key] = now
|
|
130
|
+
|
|
131
|
+
if self.tokens[key] >= 1:
|
|
132
|
+
self.tokens[key] -= 1
|
|
133
|
+
return True
|
|
134
|
+
return False
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 4. Leaky Bucket
|
|
138
|
+
|
|
139
|
+
**Concept:** Requests leak out at constant rate
|
|
140
|
+
|
|
141
|
+
**Example:** Process 10 requests/sec, queue up to 100
|
|
142
|
+
|
|
143
|
+
**Pros:**
|
|
144
|
+
- Smooths output
|
|
145
|
+
- Handles bursts
|
|
146
|
+
- Predictable rate
|
|
147
|
+
|
|
148
|
+
**Cons:**
|
|
149
|
+
- Queue management
|
|
150
|
+
- Memory usage
|
|
151
|
+
|
|
152
|
+
## Implementation Patterns
|
|
153
|
+
|
|
154
|
+
### Redis-Based Rate Limiting
|
|
155
|
+
|
|
156
|
+
**Using Fixed Window:**
|
|
157
|
+
```python
|
|
158
|
+
import redis
|
|
159
|
+
from datetime import datetime
|
|
160
|
+
|
|
161
|
+
redis_client = redis.Redis()
|
|
162
|
+
|
|
163
|
+
def rate_limit(key, max_requests, window_seconds):
|
|
164
|
+
now = datetime.now()
|
|
165
|
+
window = int(now.timestamp() / window_seconds)
|
|
166
|
+
redis_key = f"ratelimit:{key}:{window}"
|
|
167
|
+
|
|
168
|
+
current = redis_client.incr(redis_key)
|
|
169
|
+
if current == 1:
|
|
170
|
+
redis_client.expire(redis_key, window_seconds)
|
|
171
|
+
|
|
172
|
+
return current <= max_requests
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Using Sliding Window with Sorted Sets:**
|
|
176
|
+
```python
|
|
177
|
+
def sliding_window_rate_limit(key, max_requests, window_seconds):
|
|
178
|
+
now = datetime.now().timestamp()
|
|
179
|
+
cutoff = now - window_seconds
|
|
180
|
+
|
|
181
|
+
redis_key = f"ratelimit:{key}"
|
|
182
|
+
|
|
183
|
+
# Remove old entries
|
|
184
|
+
redis_client.zremrangebyscore(redis_key, 0, cutoff)
|
|
185
|
+
|
|
186
|
+
# Count current requests
|
|
187
|
+
current = redis_client.zcard(redis_key)
|
|
188
|
+
|
|
189
|
+
if current < max_requests:
|
|
190
|
+
redis_client.zadd(redis_key, {str(now): now})
|
|
191
|
+
redis_client.expire(redis_key, window_seconds)
|
|
192
|
+
return True
|
|
193
|
+
|
|
194
|
+
return False
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Middleware Pattern
|
|
198
|
+
|
|
199
|
+
**Flask Example:**
|
|
200
|
+
```python
|
|
201
|
+
from flask import request, g, jsonify
|
|
202
|
+
from functools import wraps
|
|
203
|
+
|
|
204
|
+
def rate_limit(max_requests, window_seconds):
|
|
205
|
+
def decorator(f):
|
|
206
|
+
@wraps(f)
|
|
207
|
+
def decorated_function(*args, **kwargs):
|
|
208
|
+
key = get_rate_limit_key() # IP, user ID, API key
|
|
209
|
+
|
|
210
|
+
if not rate_limiter.is_allowed(key, max_requests, window_seconds):
|
|
211
|
+
return jsonify({
|
|
212
|
+
"error": "Rate limit exceeded"
|
|
213
|
+
}), 429
|
|
214
|
+
|
|
215
|
+
return f(*args, **kwargs)
|
|
216
|
+
return decorated_function
|
|
217
|
+
return decorator
|
|
218
|
+
|
|
219
|
+
@app.route('/api/users')
|
|
220
|
+
@rate_limit(max_requests=100, window_seconds=60)
|
|
221
|
+
def get_users():
|
|
222
|
+
return jsonify(users=[...])
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Header Response
|
|
226
|
+
|
|
227
|
+
**Rate Limit Headers:**
|
|
228
|
+
```python
|
|
229
|
+
def add_rate_limit_headers(response, remaining, reset_time):
|
|
230
|
+
response.headers['X-RateLimit-Limit'] = str(max_requests)
|
|
231
|
+
response.headers['X-RateLimit-Remaining'] = str(remaining)
|
|
232
|
+
response.headers['X-RateLimit-Reset'] = str(int(reset_time.timestamp()))
|
|
233
|
+
return response
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**RFC 6585 Standard Headers:**
|
|
237
|
+
```http
|
|
238
|
+
HTTP/1.1 429 Too Many Requests
|
|
239
|
+
Retry-After: 60
|
|
240
|
+
X-RateLimit-Limit: 100
|
|
241
|
+
X-RateLimit-Remaining: 0
|
|
242
|
+
X-RateLimit-Reset: 1642233600
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Rate Limit Keys
|
|
246
|
+
|
|
247
|
+
### By IP Address
|
|
248
|
+
|
|
249
|
+
**Simple but Limited:**
|
|
250
|
+
```python
|
|
251
|
+
def get_rate_limit_key():
|
|
252
|
+
return request.remote_addr
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### By API Key
|
|
256
|
+
|
|
257
|
+
**Better for APIs:**
|
|
258
|
+
```python
|
|
259
|
+
def get_rate_limit_key():
|
|
260
|
+
api_key = request.headers.get('X-API-Key')
|
|
261
|
+
return f"apikey:{api_key}"
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### By User ID
|
|
265
|
+
|
|
266
|
+
**For Authenticated Users:**
|
|
267
|
+
```python
|
|
268
|
+
def get_rate_limit_key():
|
|
269
|
+
user_id = g.current_user.id
|
|
270
|
+
return f"user:{user_id}"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Composite Keys
|
|
274
|
+
|
|
275
|
+
**Multiple Factors:**
|
|
276
|
+
```python
|
|
277
|
+
def get_rate_limit_key():
|
|
278
|
+
user_id = g.current_user.id if g.current_user else None
|
|
279
|
+
endpoint = request.endpoint
|
|
280
|
+
return f"{user_id}:{endpoint}"
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Tiered Rate Limits
|
|
284
|
+
|
|
285
|
+
### Different Limits per Tier
|
|
286
|
+
|
|
287
|
+
**Free Tier:**
|
|
288
|
+
```python
|
|
289
|
+
FREE_TIER_LIMITS = {
|
|
290
|
+
'requests_per_minute': 60,
|
|
291
|
+
'requests_per_hour': 1000,
|
|
292
|
+
'requests_per_day': 10000
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Premium Tier:**
|
|
297
|
+
```python
|
|
298
|
+
PREMIUM_TIER_LIMITS = {
|
|
299
|
+
'requests_per_minute': 600,
|
|
300
|
+
'requests_per_hour': 100000,
|
|
301
|
+
'requests_per_day': 1000000
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Implementation:**
|
|
306
|
+
```python
|
|
307
|
+
def get_rate_limits(user_tier):
|
|
308
|
+
limits = {
|
|
309
|
+
'free': FREE_TIER_LIMITS,
|
|
310
|
+
'premium': PREMIUM_TIER_LIMITS
|
|
311
|
+
}.get(user_tier, FREE_TIER_LIMITS)
|
|
312
|
+
|
|
313
|
+
return limits
|
|
314
|
+
|
|
315
|
+
def check_rate_limit(user, endpoint):
|
|
316
|
+
limits = get_rate_limits(user.tier)
|
|
317
|
+
|
|
318
|
+
for window, max_requests in limits.items():
|
|
319
|
+
if not rate_limiter.is_allowed(
|
|
320
|
+
f"{user.id}:{endpoint}",
|
|
321
|
+
max_requests,
|
|
322
|
+
parse_window(window)
|
|
323
|
+
):
|
|
324
|
+
return False
|
|
325
|
+
return True
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Error Responses
|
|
329
|
+
|
|
330
|
+
### Standard 429 Response
|
|
331
|
+
|
|
332
|
+
**Format:**
|
|
333
|
+
```json
|
|
334
|
+
{
|
|
335
|
+
"error": {
|
|
336
|
+
"code": "RATE_LIMIT_EXCEEDED",
|
|
337
|
+
"message": "Rate limit exceeded. Try again in 60 seconds.",
|
|
338
|
+
"retry_after": 60
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Implementation:**
|
|
344
|
+
```python
|
|
345
|
+
@app.errorhandler(429)
|
|
346
|
+
def rate_limit_exceeded(error):
|
|
347
|
+
return jsonify({
|
|
348
|
+
"error": {
|
|
349
|
+
"code": "RATE_LIMIT_EXCEEDED",
|
|
350
|
+
"message": "Rate limit exceeded",
|
|
351
|
+
"retry_after": error.retry_after
|
|
352
|
+
}
|
|
353
|
+
}), 429
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## Best Practices
|
|
357
|
+
|
|
358
|
+
1. **Choose appropriate algorithm:** Sliding window for accuracy
|
|
359
|
+
2. **Use Redis for distributed:** Shared state across instances
|
|
360
|
+
3. **Set reasonable limits:** Balance protection and usability
|
|
361
|
+
4. **Include rate limit headers:** Inform clients of limits
|
|
362
|
+
5. **Return 429 status:** Standard HTTP status for rate limits
|
|
363
|
+
6. **Include Retry-After:** Tell clients when to retry
|
|
364
|
+
7. **Log rate limit hits:** Monitor for abuse patterns
|
|
365
|
+
8. **Tier limits appropriately:** Different limits per user tier
|
|
366
|
+
9. **Whitelist if needed:** Exempt certain keys/IPs
|
|
367
|
+
10. **Test thoroughly:** Ensure limits work as expected
|
|
368
|
+
|
|
369
|
+
## Common Patterns
|
|
370
|
+
|
|
371
|
+
### Per-Endpoint Limits
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
ENDPOINT_LIMITS = {
|
|
375
|
+
'/api/users': {'max': 100, 'window': 60},
|
|
376
|
+
'/api/orders': {'max': 50, 'window': 60},
|
|
377
|
+
'/api/reports': {'max': 10, 'window': 300},
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Burst Protection
|
|
382
|
+
|
|
383
|
+
```python
|
|
384
|
+
# Allow bursts but limit sustained rate
|
|
385
|
+
BURST_LIMIT = 20 # Immediate burst
|
|
386
|
+
SUSTAINED_LIMIT = 100 # Per minute
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Adaptive Rate Limiting
|
|
390
|
+
|
|
391
|
+
```python
|
|
392
|
+
def adaptive_rate_limit(user):
|
|
393
|
+
# Increase limit for good users
|
|
394
|
+
if user.reputation_score > 0.95:
|
|
395
|
+
return PREMIUM_LIMITS
|
|
396
|
+
elif user.reputation_score > 0.8:
|
|
397
|
+
return STANDARD_LIMITS
|
|
398
|
+
else:
|
|
399
|
+
return REDUCED_LIMITS
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## External API Rate Limiting
|
|
403
|
+
|
|
404
|
+
### Pattern 1: Client-Side Rate Limiting
|
|
405
|
+
|
|
406
|
+
**Respect External API Limits:**
|
|
407
|
+
```python
|
|
408
|
+
from collections import deque
|
|
409
|
+
from datetime import datetime, timedelta
|
|
410
|
+
|
|
411
|
+
class ExternalAPIRateLimiter:
|
|
412
|
+
def __init__(self, max_requests: int, time_window: int):
|
|
413
|
+
self.max_requests = max_requests
|
|
414
|
+
self.time_window = timedelta(seconds=time_window)
|
|
415
|
+
self.requests = deque()
|
|
416
|
+
|
|
417
|
+
async def acquire(self):
|
|
418
|
+
"""Acquire rate limit token."""
|
|
419
|
+
now = datetime.now()
|
|
420
|
+
|
|
421
|
+
# Remove old requests
|
|
422
|
+
while self.requests and now - self.requests[0] > self.time_window:
|
|
423
|
+
self.requests.popleft()
|
|
424
|
+
|
|
425
|
+
# Check if limit reached
|
|
426
|
+
if len(self.requests) >= self.max_requests:
|
|
427
|
+
wait_time = (self.requests[0] + self.time_window - now).total_seconds()
|
|
428
|
+
await asyncio.sleep(wait_time)
|
|
429
|
+
return await self.acquire()
|
|
430
|
+
|
|
431
|
+
# Add current request
|
|
432
|
+
self.requests.append(now)
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Pattern 2: API-Specific Rate Limits
|
|
436
|
+
|
|
437
|
+
**Different Limits per API:**
|
|
438
|
+
```python
|
|
439
|
+
class APIRateLimitManager:
|
|
440
|
+
def __init__(self):
|
|
441
|
+
self.limiters = {
|
|
442
|
+
"openweathermap": ExternalAPIRateLimiter(max_requests=60, time_window=60),
|
|
443
|
+
"watttime": ExternalAPIRateLimiter(max_requests=100, time_window=60),
|
|
444
|
+
"airnow": ExternalAPIRateLimiter(max_requests=500, time_window=3600),
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async def acquire(self, api_name: str):
|
|
448
|
+
"""Acquire rate limit for specific API."""
|
|
449
|
+
if api_name in self.limiters:
|
|
450
|
+
await self.limiters[api_name].acquire()
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Pattern 3: Retry with Rate Limit Awareness
|
|
454
|
+
|
|
455
|
+
**Handle 429 Responses:**
|
|
456
|
+
```python
|
|
457
|
+
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
|
|
458
|
+
|
|
459
|
+
class RateLimitAwareClient:
|
|
460
|
+
def __init__(self, base_url: str, api_key: str):
|
|
461
|
+
self.base_url = base_url
|
|
462
|
+
self.api_key = api_key
|
|
463
|
+
self.client = httpx.AsyncClient()
|
|
464
|
+
self.rate_limit = ExternalAPIRateLimiter(max_requests=60, time_window=60)
|
|
465
|
+
|
|
466
|
+
@retry(
|
|
467
|
+
stop=stop_after_attempt(3),
|
|
468
|
+
wait=wait_exponential(multiplier=1, min=2, max=10),
|
|
469
|
+
retry=retry_if_exception_type(httpx.HTTPStatusError)
|
|
470
|
+
)
|
|
471
|
+
async def get(self, endpoint: str):
|
|
472
|
+
"""GET request with rate limit awareness."""
|
|
473
|
+
await self.rate_limit.acquire()
|
|
474
|
+
|
|
475
|
+
response = await self.client.get(
|
|
476
|
+
f"{self.base_url}/{endpoint}",
|
|
477
|
+
headers={"Authorization": f"Bearer {self.api_key}"}
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
# Handle 429 (Too Many Requests)
|
|
481
|
+
if response.status_code == 429:
|
|
482
|
+
retry_after = int(response.headers.get("Retry-After", 60))
|
|
483
|
+
await asyncio.sleep(retry_after)
|
|
484
|
+
raise httpx.HTTPStatusError("Rate limit exceeded", request=response.request, response=response)
|
|
485
|
+
|
|
486
|
+
response.raise_for_status()
|
|
487
|
+
return response.json()
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
**See Also:**
|
|
491
|
+
- `external-api-integration.md` - Comprehensive external API integration patterns
|
|
492
|
+
|
|
493
|
+
## Tools
|
|
494
|
+
|
|
495
|
+
### Open Source
|
|
496
|
+
|
|
497
|
+
- **Redis:** Distributed rate limiting
|
|
498
|
+
- **nginx rate limiting:** Built-in module
|
|
499
|
+
- **Kong:** API gateway with rate limiting
|
|
500
|
+
- **Envoy:** Service mesh with rate limiting
|
|
501
|
+
|
|
502
|
+
### Commercial
|
|
503
|
+
|
|
504
|
+
- **CloudFlare:** DDoS protection and rate limiting
|
|
505
|
+
- **AWS API Gateway:** Built-in throttling
|
|
506
|
+
- **Azure API Management:** Rate limit policies
|
|
507
|
+
|