Skip to content

fix: Split apache-libcloud versions for Python compatibility#619

Merged
dahagag merged 8 commits into
ascoderu:masterfrom
dahagag:fix/split-libcloud-versions
Jun 1, 2026
Merged

fix: Split apache-libcloud versions for Python compatibility#619
dahagag merged 8 commits into
ascoderu:masterfrom
dahagag:fix/split-libcloud-versions

Conversation

@dahagag

@dahagag dahagag commented Jun 1, 2026

Copy link
Copy Markdown
Member

Problem

PR #618 upgraded apache-libcloud to 3.8.0 for Python 3.12 compatibility, but introduced a production bug:

  • KeyError: 'zone_name' in Cloudflare DNS driver (cloudflare.py:520)
  • Client registration fails - blocks all new deployments

Root cause: apache-libcloud Cloudflare driver is unstable across recent versions:

  • 3.2.0: Last stable version (pre-June 2022) but incompatible with Python 3.12
  • 3.6.0: RecordAlreadyExistsError missing record_id parameter
  • 3.8.0: KeyError: 'zone_name' in _to_record()

Solution

1. Split apache-libcloud Versions

Use Docker container isolation to run different versions per service:

  • Server (api, worker): Python 3.9 + libcloud 3.2.0 (stable Cloudflare DNS)
  • Client (webapp, client): Python 3.12 + libcloud 3.8.0 (Python 3.12 support)

Implementation:

  • requirements.txt: apache-libcloud==3.2.0 (server default)
  • requirements-webapp.txt: apache-libcloud==3.8.0 (client override)
  • Client Dockerfile installs base package without [opwen_email_server] extra to avoid version conflict

2. RabbitMQ 4.0+ Compatibility

Fixed deprecation warnings causing worker instability:

  • Define all 7 task queues explicitly as durable Queue objects
  • Disable worker remote control to prevent transient pidbox queues
  • Set worker_prefetch_multiplier=1 to avoid deprecated global_qos
  • Fixes: Feature 'transient_nonexcl_queues' is deprecated

3. Clean Integration Test Dependencies

Created requirements-integration.txt for server dependencies needed only by AzureIoc:

  • Separates production client deps from integration test deps
  • Production: client.env → default Ioc → minimal dependencies
  • Integration: webapp.envAzureIoc → full server dependencies
  • Dependencies: applicationinsights, msgpack, sendgrid, pyzmail36, azure-servicebus, connexion, jsonschema, referencing, wikipedia

Testing

Local Integration Tests (BUILD_TARGET=runtime):

  • All services started successfully
  • 3 clients registered
  • Email upload/reception working
  • RabbitMQ 4.3.1 compatible

Version Isolation Verified:

docker compose exec webapp pip show apache-libcloud | grep Version
# Version: 3.8.0

docker compose exec api pip show apache-libcloud | grep Version
# Version: 3.2.0

docker compose exec worker pip show apache-libcloud | grep Version  
# Version: 3.2.0

Changes

Modified Files

  • requirements.txt: Pin apache-libcloud 3.2.0 for server (Python 3.9)
  • requirements-webapp.txt: Override to apache-libcloud 3.8.0 for client (Python 3.12)
  • docker/client/Dockerfile: Install base package without [opwen_email_server] extra, add integration deps to runtime stage
  • opwen_email_server/integration/celery.py: Add explicit durable queue definitions, disable remote control
  • opwen_email_server/services/dns.py: Refactor with type-safe error handling
  • tests/opwen_email_server/integration/test_celery.py: Update test queue to be durable

New Files

  • requirements-integration.txt: Server dependencies for AzureIoc integration testing only

CI/CD

  • Applied yapf and isort formatting
  • All linting passes (hadolint, flake8)

Deployment Plan

  1. Merge this PR
  2. Release as v0.8.9
  3. Deploy to mailserver.lokole.ca (fixes v0.8.8 KeyError bug)
  4. Test client registration with real Cloudflare DNS
  5. Verify SendGrid webhook functionality

Breaking Changes

None - backward compatible with existing deployments.

Related

  • Closes issue with v0.8.8 production Cloudflare DNS errors
  • Fixes RabbitMQ 4.0+ deprecation warnings
  • Improves container dependency architecture

- Server (Python 3.9): apache-libcloud==3.2.0 (stable Cloudflare DNS)
- Client (Python 3.12): apache-libcloud==3.8.0 (Python 3.12 support)

Client Dockerfile installs requirements-webapp.txt after requirements.txt,
so libcloud 3.8.0 overrides 3.2.0 for the client container only.

Fixes Cloudflare DNS issues:
- libcloud 3.6.0: RecordAlreadyExistsError constructor bug
- libcloud 3.8.0: KeyError 'zone_name' in Cloudflare driver
- libcloud 3.2.0: Proven stable with Cloudflare, incompatible with Py3.12

Tested:
- Server: Python 3.9 + libcloud 3.2.0 (all 8 DNS tests pass)
- Client: Python 3.12 + libcloud 3.8.0 (imports work correctly)
The client Dockerfile was installing the package with [opwen_email_server] extra,
which pulled in server dependencies (requirements.txt with libcloud 3.2.0).
This conflicted with the client's libcloud 3.8.0.

Client only needs the base package dependencies (requirements-webapp.txt).
dahagag added 3 commits June 1, 2026 20:37
RabbitMQ 4.0+ deprecated transient non-exclusive queues. The integration
test was creating a queue without durable=True, causing CI failures with:
InternalError: Queue.declare: (541) INTERNAL_ERROR - Feature
`transient_nonexcl_queues` is deprecated.
RabbitMQ 4.0+ deprecated transient non-exclusive queues. This fix:

1. Explicitly defines all task queues as durable using Kombu Queue objects
2. Disables remote control (worker_enable_remote_control=False) to prevent
   creation of non-durable pidbox queues that trigger the deprecation error
3. Updates test queue to be durable

Without these changes, Celery workers fail to start with:
  amqp.exceptions.InternalError: Queue.declare: (541) INTERNAL_ERROR
  Feature `transient_nonexcl_queues` is deprecated.

Tested successfully with RabbitMQ 4.3.1 - all integration tests pass.
dahagag added 2 commits June 1, 2026 23:00
…tion.txt

- Created requirements-integration.txt with server dependencies needed by AzureIoc
- Updated Dockerfile to install integration deps in both builder and runtime stages
- Production client (client.env) uses default Ioc without server dependencies
- Integration tests (webapp.env) use AzureIoc with full server dependencies
- Integration tests now pass successfully with BUILD_TARGET=runtime
- Define all 7 task queues explicitly as durable Queue objects
- Disable worker remote control to prevent transient pidbox queues
- Set worker_prefetch_multiplier=1 to avoid deprecated global_qos
- Fixes 'Feature transient_nonexcl_queues is deprecated' errors
- Integration tests pass with RabbitMQ 4.3.1
@dahagag dahagag merged commit 45bb3b5 into ascoderu:master Jun 1, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant