localqueue 0.3.3__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {localqueue-0.3.3 → localqueue-0.3.4}/CHANGELOG.md +5 -0
  2. {localqueue-0.3.3 → localqueue-0.3.4}/PKG-INFO +1 -1
  3. {localqueue-0.3.3 → localqueue-0.3.4}/docs/release.md +1 -1
  4. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/services/queue_worker.py +2 -0
  5. {localqueue-0.3.3 → localqueue-0.3.4}/pyproject.toml +1 -1
  6. {localqueue-0.3.3 → localqueue-0.3.4}/tests/test_cli.py +50 -0
  7. {localqueue-0.3.3 → localqueue-0.3.4}/uv.lock +1 -1
  8. {localqueue-0.3.3 → localqueue-0.3.4}/.gitignore +0 -0
  9. {localqueue-0.3.3 → localqueue-0.3.4}/LICENSE +0 -0
  10. {localqueue-0.3.3 → localqueue-0.3.4}/README.md +0 -0
  11. {localqueue-0.3.3 → localqueue-0.3.4}/docs/api.md +0 -0
  12. {localqueue-0.3.3 → localqueue-0.3.4}/docs/compare.md +0 -0
  13. {localqueue-0.3.3 → localqueue-0.3.4}/docs/index.md +0 -0
  14. {localqueue-0.3.3 → localqueue-0.3.4}/docs/operational-maturity.md +0 -0
  15. {localqueue-0.3.3 → localqueue-0.3.4}/docs/queues.md +0 -0
  16. {localqueue-0.3.3 → localqueue-0.3.4}/docs/retries.md +0 -0
  17. {localqueue-0.3.3 → localqueue-0.3.4}/docs/stability.md +0 -0
  18. {localqueue-0.3.3 → localqueue-0.3.4}/examples/email_worker.py +0 -0
  19. {localqueue-0.3.3 → localqueue-0.3.4}/examples/enqueue_email.py +0 -0
  20. {localqueue-0.3.3 → localqueue-0.3.4}/examples/process_webhook.sh +0 -0
  21. {localqueue-0.3.3 → localqueue-0.3.4}/examples/retry_demo.py +0 -0
  22. {localqueue-0.3.3 → localqueue-0.3.4}/examples/sqlite_concurrency_benchmark.py +0 -0
  23. {localqueue-0.3.3 → localqueue-0.3.4}/examples/sqlite_process_harness.py +0 -0
  24. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/__init__.py +0 -0
  25. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/cli.py +0 -0
  26. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/cli_commands.py +0 -0
  27. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/cli_support.py +0 -0
  28. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/cli_worker_commands.py +0 -0
  29. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/failure.py +0 -0
  30. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/paths.py +0 -0
  31. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/queue.py +0 -0
  32. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/__init__.py +0 -0
  33. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/stores/__init__.py +0 -0
  34. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/stores/_shared.py +0 -0
  35. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/stores/base.py +0 -0
  36. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/stores/lmdb.py +0 -0
  37. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/stores/memory.py +0 -0
  38. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/stores/sqlite.py +0 -0
  39. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/retry/tenacity.py +0 -0
  40. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/services/__init__.py +0 -0
  41. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/stores/__init__.py +0 -0
  42. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/stores/_shared.py +0 -0
  43. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/stores/base.py +0 -0
  44. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/stores/lmdb.py +0 -0
  45. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/stores/memory.py +0 -0
  46. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/stores/sqlite.py +0 -0
  47. {localqueue-0.3.3 → localqueue-0.3.4}/localqueue/worker.py +0 -0
  48. {localqueue-0.3.3 → localqueue-0.3.4}/tests/test_process_harness.py +0 -0
  49. {localqueue-0.3.3 → localqueue-0.3.4}/tests/test_queue.py +0 -0
  50. {localqueue-0.3.3 → localqueue-0.3.4}/tests/test_retry.py +0 -0
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.4
4
+
5
+ - Keep `queue exec` and `queue process` alive in `--forever --block` mode when the queue starts empty.
6
+ - Preserve the batch empty-queue exit behavior for non-forever workers.
7
+
3
8
  ## 0.3.3
4
9
 
5
10
  - Split queue and retry store implementations into dedicated modules.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localqueue
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: Durable local queues for Python, with persistent retry state powered by Tenacity.
5
5
  Project-URL: Homepage, https://brunoportis.github.io/localqueue/
6
6
  Project-URL: Documentation, https://brunoportis.github.io/localqueue/
@@ -108,4 +108,4 @@ Before `1.0.0`, use this convention:
108
108
 
109
109
  ## Current Release
110
110
 
111
- The current planned release is `0.3.3`.
111
+ The current planned release is `0.3.4`.
@@ -352,6 +352,8 @@ def process_queue_messages(
352
352
  )
353
353
  )
354
354
  if empty_queue:
355
+ if options.forever and options.block:
356
+ continue
355
357
  return handle_empty_queue(err_console, processed)
356
358
  assert iteration is not None
357
359
  if handle_processed_queue_result(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "localqueue"
3
- version = "0.3.3"
3
+ version = "0.3.4"
4
4
  description = "Durable local queues for Python, with persistent retry state powered by Tenacity."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -58,6 +58,7 @@ from localqueue.cli_worker_commands import (
58
58
  )
59
59
  from localqueue.services.queue_worker import (
60
60
  QueueIterationContext as _QueueIterationContext,
61
+ QueueIterationResult as _QueueIterationResult,
61
62
  QueueWorkerOptions as _QueueWorkerOptions,
62
63
  _CommandExecutionError,
63
64
  _CommandNotFoundError,
@@ -1747,6 +1748,55 @@ class CliTests(unittest.TestCase):
1747
1748
  self.assertEqual(console.values, [])
1748
1749
  self.assertEqual(err_console.messages, ["[yellow]queue is empty[/yellow]"])
1749
1750
 
1751
+ def test_process_queue_messages_keeps_waiting_when_forever_blocking_is_empty(
1752
+ self,
1753
+ ) -> None:
1754
+ queue = PersistentQueue("emails", store=MemoryQueueStore())
1755
+ console = _JsonConsole()
1756
+ err_console = _JsonConsole()
1757
+ shutdown = _ShutdownState()
1758
+
1759
+ def stop_after_second_poll(
1760
+ context: _QueueIterationContext,
1761
+ ) -> tuple[_QueueIterationResult | None, SQLiteAttemptStore | None, bool]:
1762
+ if shutdown.requested:
1763
+ return None, None, True
1764
+ shutdown.requested = True
1765
+ self.assertTrue(context.forever)
1766
+ self.assertTrue(context.block)
1767
+ return None, None, True
1768
+
1769
+ with mock.patch(
1770
+ "localqueue.services.queue_worker.process_queue_iteration",
1771
+ side_effect=stop_after_second_poll,
1772
+ ) as process_iteration:
1773
+ result = _process_queue_messages(
1774
+ queue,
1775
+ lambda payload: payload,
1776
+ console=console,
1777
+ err_console=err_console,
1778
+ shutdown=shutdown,
1779
+ options=_QueueWorkerOptions(
1780
+ retry_store_path=self._retry_store_path(),
1781
+ max_jobs=1,
1782
+ forever=True,
1783
+ max_tries=1,
1784
+ worker_id="worker-a",
1785
+ block=True,
1786
+ timeout=None,
1787
+ idle_sleep=0.001,
1788
+ release_delay=0.0,
1789
+ dead_letter_on_exhaustion=True,
1790
+ log_events=False,
1791
+ mode="process",
1792
+ ),
1793
+ )
1794
+
1795
+ self.assertEqual(result, 0)
1796
+ self.assertEqual(console.values, [{"state": "stopped", "processed": 0}])
1797
+ self.assertEqual(err_console.messages, [])
1798
+ self.assertEqual(process_iteration.call_count, 1)
1799
+
1750
1800
  def test_process_queue_iteration_handles_forever_empty_queue_without_blocking(
1751
1801
  self,
1752
1802
  ) -> None:
@@ -200,7 +200,7 @@ wheels = [
200
200
 
201
201
  [[package]]
202
202
  name = "localqueue"
203
- version = "0.3.3"
203
+ version = "0.3.4"
204
204
  source = { editable = "." }
205
205
  dependencies = [
206
206
  { name = "tenacity" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes