nexus-queue 0.1.1__tar.gz → 0.1.2__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.
Files changed (26) hide show
  1. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/CHANGELOG.md +7 -0
  2. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/PKG-INFO +1 -1
  3. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/config.py +15 -0
  4. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/lifecycle.py +26 -0
  5. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/pyproject.toml +1 -1
  6. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/.gitignore +0 -0
  7. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/.python-version +0 -0
  8. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/README.md +0 -0
  9. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/__init__.py +0 -0
  10. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/app.py +0 -0
  11. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/broker.py +0 -0
  12. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/delayed.py +0 -0
  13. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/envelope.py +0 -0
  14. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/exceptions.py +0 -0
  15. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/handlers.py +0 -0
  16. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/kicker.py +0 -0
  17. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/middleware/__init__.py +0 -0
  18. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/middleware/metrics.py +0 -0
  19. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/middleware/retry_dlq.py +0 -0
  20. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/naming.py +0 -0
  21. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/pipeline.py +0 -0
  22. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/ports.py +0 -0
  23. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/publisher.py +0 -0
  24. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/py.typed +0 -0
  25. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/nexus_queue/tracing.py +0 -0
  26. {nexus_queue-0.1.1 → nexus_queue-0.1.2}/tests/test_integration.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.2](https://github.com/Zetesis-Labs/PayloadAgents/compare/nexus-queue-v0.1.1...nexus-queue-v0.1.2) (2026-06-17)
4
+
5
+
6
+ ### Features
7
+
8
+ * **nexus-queue:** serve worker Prometheus metrics over HTTP ([#100](https://github.com/Zetesis-Labs/PayloadAgents/issues/100)) ([cb5af8a](https://github.com/Zetesis-Labs/PayloadAgents/commit/cb5af8aaa944681358175e425ef88b2ee9e282be))
9
+
3
10
  ## [0.1.1](https://github.com/Zetesis-Labs/PayloadAgents/compare/nexus-queue-v0.1.0...nexus-queue-v0.1.1) (2026-06-17)
4
11
 
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nexus-queue
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Nexus-Queue — portable taskiq + Redis Streams worker runtime: namespaced streams, versioned envelope, ports-and-adapters, retry/DLQ/idempotency/tracing/metrics middleware.
5
5
  Project-URL: Homepage, https://github.com/Zetesis-Labs/PayloadAgents
6
6
  Project-URL: Repository, https://github.com/Zetesis-Labs/PayloadAgents
@@ -69,6 +69,21 @@ class RuntimeConfig(BaseModel):
69
69
  description="Approx MAXLEN for the dead-letter stream; 0 = unbounded.",
70
70
  )
71
71
 
72
+ # ── Observability ──────────────────────────────────────────────────────
73
+ metrics_port: int | None = Field(
74
+ default=None,
75
+ gt=0,
76
+ lt=65_536,
77
+ description=(
78
+ "If set, the worker serves Prometheus metrics on this port via an "
79
+ "in-process HTTP server (scrape target for a ServiceMonitor). The "
80
+ "taskiq worker has no HTTP server otherwise, so its consume counters "
81
+ "are invisible without this. Run the worker single-process "
82
+ "(taskiq --workers 1) and scale by pods, or the port will collide. "
83
+ "None disables it."
84
+ ),
85
+ )
86
+
72
87
  # ── Logging ────────────────────────────────────────────────────────────
73
88
  log_level: str = Field(default="INFO")
74
89
 
@@ -11,12 +11,15 @@ import logging
11
11
 
12
12
  import redis.asyncio as aioredis
13
13
  import structlog
14
+ from prometheus_client import start_http_server
14
15
  from taskiq import AsyncBroker, TaskiqEvents, TaskiqState
15
16
 
16
17
  from nexus_queue.config import RuntimeConfig
17
18
  from nexus_queue.delayed import DelayedRetryPoller
18
19
  from nexus_queue.naming import idempotency_redis_key
19
20
 
21
+ logger = structlog.get_logger("nexus_queue.lifecycle")
22
+
20
23
 
21
24
  class IdempotencyStore:
22
25
  """Redis mark-done dedup keyed by the message's ``nq_idem`` label.
@@ -71,6 +74,28 @@ def configure_logging(config: RuntimeConfig) -> None:
71
74
  )
72
75
 
73
76
 
77
+ def _start_metrics_server(config: RuntimeConfig) -> None:
78
+ """Serve the Prometheus registry over HTTP from the worker process.
79
+
80
+ The consume counters/histogram live in this process; the kicker is a
81
+ separate pod with its own registry, so without this the worker's metrics
82
+ have no scrape endpoint. Best-effort: a metrics-server failure (e.g. a
83
+ port collision when mistakenly run multi-process) must never take the
84
+ worker down."""
85
+ if config.metrics_port is None:
86
+ return
87
+ try:
88
+ start_http_server(config.metrics_port)
89
+ logger.info("metrics-server-started", port=config.metrics_port)
90
+ except OSError as exc:
91
+ logger.warning(
92
+ "metrics-server-failed",
93
+ port=config.metrics_port,
94
+ error=str(exc),
95
+ hint="run the worker single-process (taskiq --workers 1)",
96
+ )
97
+
98
+
74
99
  def register_lifecycle(
75
100
  broker: AsyncBroker,
76
101
  config: RuntimeConfig,
@@ -89,6 +114,7 @@ def register_lifecycle(
89
114
  async def _startup(state: TaskiqState) -> None: # pyright: ignore[reportUnusedFunction]
90
115
  state.nexus_config = config
91
116
  state.nexus_adapters = adapters
117
+ _start_metrics_server(config)
92
118
  store = IdempotencyStore(config)
93
119
  await store.startup()
94
120
  state.nexus_idempotency = store
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nexus-queue"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  description = "Nexus-Queue — portable taskiq + Redis Streams worker runtime: namespaced streams, versioned envelope, ports-and-adapters, retry/DLQ/idempotency/tracing/metrics middleware."
5
5
  requires-python = ">=3.12"
6
6
  readme = "README.md"
File without changes
File without changes
File without changes