Files
unstract/workers/pyproject.toml
Chandrasekharan M 0c0c8c1034 UN-2793 [FEAT] Add retry logic with exponential backoff to SDK1 (#1564)
* UN-2793 [FEAT] Add retry logic with exponential backoff to SDK1

Implemented automatic retry logic for platform and prompt service calls
with configurable exponential backoff, comprehensive test coverage, and
CI integration.

Features:
- Exponential backoff with jitter for transient failures
- Configurable via environment variables (MAX_RETRIES, MAX_TIME, BASE_DELAY, etc.)
- Retries ConnectionError, Timeout, HTTPError (502/503/504), OSError
- 67 tests with 100% pass rate
- CI integration with test reporting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* [SECURITY] Use full commit SHA for sticky-pull-request-comment action

Replace tag reference with full commit SHA for better security:
- marocchino/sticky-pull-request-comment@v2 → @7737449 (v2.9.4)

This prevents potential supply chain attacks where tags could be moved
to point to malicious code. Commit SHAs are immutable.

Fixes SonarQube security hotspot for external GitHub action.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* [FIX] Allow retryable HTTP errors (502/503/504) to propagate for retry

Fixed HTTPError handling in _get_adapter_configuration to check status
codes and re-raise retryable errors (502, 503, 504) so the retry
decorator can handle them. Non-retryable errors are still converted
to SdkError as before.

Changes:
- Check HTTPError status code before converting to SdkError
- Re-raise HTTPError for 502/503/504 to allow retry decorator to retry
- Added parametrized test for all retryable status codes (502, 503, 504)
- All 12 platform tests pass

This fixes a bug where 502/503/504 errors were not being retried
because they were converted to SdkError before the retry decorator
could see them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* [FIX] Use pytest.approx() for floating point comparisons in tests

Replaced direct equality comparisons (==) with pytest.approx() for
floating point values to avoid precision issues and satisfy SonarQube
code quality check (python:S1244).

Changes in test_retry_utils.py:
- test_exponential_backoff_without_jitter: Use pytest.approx() for 1.0, 2.0, 4.0, 8.0
- test_max_delay_cap: Use pytest.approx() for 5.0

This is the proper way to compare floating point values in tests,
accounting for floating point precision limitations.

All 4 TestCalculateDelay tests pass.

Fixes SonarQube: python:S1244 - Do not perform equality checks with
floating point values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* minor: Addressed code smells, ruff fixes

* misc: Fixed tox config for sdk1 tests

* misc: Ruff issues fixed

* misc: tox tests fixed

* prompt service lock file for venv

* updated lock files for backend and prompt-service

* UN-2793 [FEAT] Update to unstract-sdk v0.78.0 with retry logic support (#1567)

[FEAT] Update unstract-sdk to v0.78.0 across all services and tools

- Updated unstract-sdk dependency from v0.77.3 to v0.78.0 in all pyproject.toml files
  - Main repository, backend, workers, platform-service, prompt-service
  - filesystem and tool-registry modules
- Updated tool requirements.txt files (structure, classifier, text_extractor)
- Bumped tool versions in properties.json:
  - Structure tool: 0.0.88 → 0.0.89
  - Classifier tool: 0.0.68 → 0.0.69
  - Text extractor tool: 0.0.64 → 0.0.65
- Updated tool versions in backend/sample.env and public_tools.json
- Regenerated all uv.lock files with new SDK version

This update brings in the retry logic with exponential backoff from unstract-sdk v0.78.0

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Chandrasekharan M <117059509+chandrasekharan-zipstack@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-09 10:48:19 +05:30

195 lines
4.9 KiB
TOML

[project]
name = "unstract-workers"
version = "1.0.0"
description = "Lightweight Celery workers for Unstract platform"
authors = [
{name = "Unstract Team", email = "support@unstract.com"},
]
# readme = "README.md" # Temporarily disabled for Docker build
license = {text = "AGPL-3.0"}
requires-python = ">=3.12"
dependencies = [
# Worker runtime
"celery>=5.5.3", # Latest stable version - AMQP support built into core
# HTTP clients and utilities (merged from shared package)
"requests>=2.31.0,<3.0.0", # HTTP client for internal API calls
"urllib3>=1.26.0", # HTTP utilities and retry strategies
"httpx>=0.27.0", # Async HTTP client
"python-dotenv>=1.0.0,<2.0.0", # Environment variable loading
# WebSocket support for log consumer
"python-socketio>=5.9.0", # Socket.IO client for emitting log events
# Monitoring and system utilities
"prometheus-client>=0.17.0,<1.0.0", # Metrics collection
"psutil>=5.9.0,<6.0.0", # System resource monitoring
# Essential Unstract packages - with Azure support for connectors
"unstract-sdk[azure]~=0.78.0", # Core SDK with Azure connector support
"unstract-connectors",
"unstract-core",
"unstract-flags",
"unstract-tool-registry",
"unstract-tool-sandbox",
"unstract-workflow-execution",
"unstract-filesystem",
# Caching
"redis>=4.5.0,<6.0.0", # Redis client for worker cache access
# Note: Using dataclasses instead of pydantic for lightweight typing
# Custom implementations replace tenancy (retry), pybreaker (circuit breaker)
# - python-dateutil: Standard datetime module sufficient
]
[dependency-groups]
dev = [
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-mock>=3.11.0",
"pytest-cov>=4.1.0",
"black>=23.7.0",
"isort>=5.12.0",
"flake8>=6.0.0",
"mypy>=1.5.0"
]
test = [
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"pytest-mock>=3.11.0",
"pytest-cov>=4.1.0",
"factory-boy>=3.3.0",
"responses>=0.23.0"
]
deploy = [
# Minimal production dependencies - most are already in main deps
# Note: Workers don't need WSGI servers or profiling tools
# OpenTelemetry for tracing
# Keep versions empty and let uv decide version
# since we use no code instrumentation and don't use in code
"opentelemetry-distro",
"opentelemetry-exporter-otlp",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["shared"]
[tool.black]
line-length = 88
target-version = ['py312']
include = '\.pyi?$'
extend-exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| build
| dist
)/
'''
[tool.isort]
profile = "black"
multi_line_output = 3
line_length = 88
known_first_party = [
"shared",
"api_deployment",
"general",
"file_processing",
"callback"
]
[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
[[tool.mypy.overrides]]
module = [
"celery.*",
"kombu.*",
"prometheus_client.*",
"psutil.*"
]
ignore_missing_imports = true
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--verbose",
"--cov=shared",
"--cov=api_deployment",
"--cov=general",
"--cov=file_processing",
"--cov=callback",
"--cov-report=term-missing",
"--cov-report=html",
"--cov-report=xml"
]
markers = [
"unit: Unit tests",
"integration: Integration tests",
"slow: Slow tests"
]
[tool.coverage.run]
source = [
"shared",
"api_deployment",
"general",
"file_processing",
"callback"
]
omit = [
"*/tests/*",
"*/test_*.py",
"*/*_test.py"
]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if settings.DEBUG",
"raise AssertionError",
"raise NotImplementedError",
"if 0:",
"if __name__ == .__main__.:",
"class .*\\bProtocol\\):",
"@(abc\\.)?abstractmethod"
]
[tool.uv.sources]
unstract-filesystem = { path = "../unstract/filesystem", editable = true }
unstract-workflow-execution = { path = "../unstract/workflow-execution", editable = true }
unstract-tool-sandbox = { path = "../unstract/tool-sandbox", editable = true }
unstract-tool-registry = { path = "../unstract/tool-registry", editable = true }
unstract-flags = { path = "../unstract/flags", editable = true }
unstract-connectors = { path = "../unstract/connectors", editable = true }
unstract-core = { path = "../unstract/core", editable = true }