serverish 2.0.3__tar.gz → 2.0.5__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 (60) hide show
  1. {serverish-2.0.3 → serverish-2.0.5}/PKG-INFO +1 -1
  2. {serverish-2.0.3 → serverish-2.0.5}/pyproject.toml +1 -1
  3. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/exceptions.py +9 -0
  4. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_callback_sub.py +9 -3
  5. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_reader.py +24 -1
  6. {serverish-2.0.3 → serverish-2.0.5}/LICENSE +0 -0
  7. {serverish-2.0.3 → serverish-2.0.5}/README.md +0 -0
  8. {serverish-2.0.3 → serverish-2.0.5}/serverish/__init__.py +0 -0
  9. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/__init__.py +0 -0
  10. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/asyncio_util_functions.py +0 -0
  11. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/collector.py +0 -0
  12. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/datetime.py +0 -0
  13. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/fifoset.py +0 -0
  14. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/hasstatuses.py +0 -0
  15. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/idmanger.py +0 -0
  16. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/iterators.py +0 -0
  17. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/manageable.py +0 -0
  18. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/singleton.py +0 -0
  19. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/status.py +0 -0
  20. {serverish-2.0.3 → serverish-2.0.5}/serverish/base/task_manager.py +0 -0
  21. {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/__init__.py +0 -0
  22. {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/connection.py +0 -0
  23. {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/connection_jets.py +0 -0
  24. {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/connection_nats.py +0 -0
  25. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/__init__.py +0 -0
  26. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/live_document.py +0 -0
  27. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/logging.py +0 -0
  28. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/messenger.py +0 -0
  29. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_cmd_pub.py +0 -0
  30. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_cmd_sub.py +0 -0
  31. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_core_pub.py +0 -0
  32. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_core_read.py +0 -0
  33. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_core_sub.py +0 -0
  34. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_document_read.py +0 -0
  35. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_journal_pub.py +0 -0
  36. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_journal_read.py +0 -0
  37. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_progress_pub.py +0 -0
  38. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_progress_read.py +0 -0
  39. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_publisher.py +0 -0
  40. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_rpc_req.py +0 -0
  41. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_rpc_resp.py +0 -0
  42. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_single_pub.py +0 -0
  43. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_single_read.py +0 -0
  44. {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msgvalidator.py +0 -0
  45. {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/__init__.py +0 -0
  46. {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/bridge.py +0 -0
  47. {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/factory.py +0 -0
  48. {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/monitored.py +0 -0
  49. {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/monitored_nats.py +0 -0
  50. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/config.schema.json +0 -0
  51. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/default.schema.json +0 -0
  52. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/include/timestamp.schema.json +0 -0
  53. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/journal.schema.json +0 -0
  54. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/meta.schema.json +0 -0
  55. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/program_current_state.schema.json +0 -0
  56. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/program_state.schema.json +0 -0
  57. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/progress.schema.json +0 -0
  58. {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/telemetry.schema.json +0 -0
  59. {serverish-2.0.3 → serverish-2.0.5}/serverish/services/TODO.txt +0 -0
  60. {serverish-2.0.3 → serverish-2.0.5}/serverish/slog.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serverish
3
- Version: 2.0.3
3
+ Version: 2.0.5
4
4
  Summary: helpers for server alike projects
5
5
  License-File: LICENSE
6
6
  Author: Mikołaj Kałuszyński
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "serverish"
3
- version = "2.0.3"
3
+ version = "2.0.5"
4
4
  description = "helpers for server alike projects"
5
5
  authors = ["Mikołaj Kałuszyński", "MMME team"]
6
6
  readme = "README.md"
@@ -7,6 +7,15 @@ class MessengerNotConnected(Exception):
7
7
  class MessengerReaderStopped(Exception):
8
8
  pass
9
9
 
10
+ class MessengerReaderConfigError(ValueError):
11
+ """Raised when a MsgReader is misconfigured (e.g. missing required start marker).
12
+
13
+ This is a fatal error — the same configuration will never succeed against
14
+ the NATS server. The reader stops and this exception propagates out of
15
+ ``async for`` loops so callers fail loudly instead of retrying forever.
16
+ """
17
+ pass
18
+
10
19
  class MessengerReaderAlreadyOpen(RuntimeError):
11
20
  pass
12
21
 
@@ -42,7 +42,9 @@ class MsgCallbackSubscriber(MsgReader):
42
42
  Args:
43
43
  callback: a callback function to call on each message, may be asynchronous
44
44
  callback is called with two arguments: message dict and metadata dict,
45
- and should return True to continue reading messages, False to stop
45
+ and may return False to stop reading messages. Any other return value
46
+ (including None — i.e. callbacks with no explicit return — and True)
47
+ keeps the subscription running.
46
48
  """
47
49
  self.callback = callback
48
50
  if asyncio.iscoroutinefunction(callback):
@@ -59,7 +61,7 @@ class MsgCallbackSubscriber(MsgReader):
59
61
  assert scb is not None or acb is not None
60
62
  assert not (scb is not None and acb is not None)
61
63
  cb = scb or acb
62
- cont = True
64
+ cont: object = True
63
65
  log.debug(f"Entering sync interation{self}")
64
66
  async for data, meta in self:
65
67
  try:
@@ -74,7 +76,11 @@ class MsgCallbackSubscriber(MsgReader):
74
76
  break
75
77
  except Exception as e:
76
78
  log.exception(f'Error in callback {cb} for message {meta}{str(data):20}: {e}')
77
- if not cont or self._stop_event.is_set() :
79
+ # Stop only on explicit False — None (the implicit "no return" value
80
+ # of a Python function) and any truthy value keep the subscription
81
+ # alive. Treating None as "stop" would silently kill any callback
82
+ # that doesn't bother returning anything, which is the common case.
83
+ if cont is False or self._stop_event.is_set():
78
84
  break
79
85
  log.debug(f"Exiting sync interation{self}")
80
86
 
@@ -12,12 +12,14 @@ from uuid import uuid4
12
12
 
13
13
 
14
14
  import nats.errors
15
+ import nats.js.errors
15
16
  import param
16
17
  from nats.js import JetStreamContext
17
18
  from nats.js.api import DeliverPolicy, ConsumerConfig
18
19
 
19
20
  from serverish.base import wait_for_psce
20
- from serverish.base.exceptions import (MessengerReaderStopped, MessengerNotConnected,
21
+ from serverish.base.exceptions import (MessengerReaderStopped, MessengerReaderConfigError,
22
+ MessengerNotConnected,
21
23
  MessengerReaderAlreadyOpen, MessengerRequestTimeout)
22
24
  from serverish.base.fifoset import FifoSet
23
25
  from serverish.messenger import Messenger
@@ -105,6 +107,17 @@ class MsgReader(MsgDriver):
105
107
  super().__init__(subject=subject, parent=parent,
106
108
  deliver_policy=deliver_policy, opt_start_time=opt_start_time, consumer_cfg=consumer_cfg_defaults,
107
109
  **kwargs)
110
+ # Validate deliver_policy ↔ start-marker consistency up front so
111
+ # callers get a clear error at construction time rather than an
112
+ # opaque NATS 400 error buried inside the read loop.
113
+ if self.deliver_policy == 'by_start_time' and self.opt_start_time is None:
114
+ raise ValueError(
115
+ "deliver_policy='by_start_time' requires opt_start_time to be set"
116
+ )
117
+ if self.deliver_policy == 'by_start_sequence' and self.consumer_cfg.get('opt_start_seq') is None:
118
+ raise ValueError(
119
+ "deliver_policy='by_start_sequence' requires opt_start_seq to be set in consumer_cfg"
120
+ )
108
121
  log.debug(f"Created {self}")
109
122
 
110
123
 
@@ -384,6 +397,16 @@ class MsgReader(MsgDriver):
384
397
  st.logput(f'{e.task}-err')
385
398
  st.error = e.error
386
399
  self._last_error = e.error # Track for health monitoring
400
+ # Fatal NATS API errors (4xx): the same request will never
401
+ # succeed — stop retrying immediately and surface a clear
402
+ # MessengerReaderConfigError to the caller.
403
+ if isinstance(e.error, (nats.js.errors.BadRequestError,
404
+ nats.js.errors.NotFoundError)):
405
+ log.error(st.fmt(f"fatal NATS error (not retrying): {e.error}"))
406
+ self._stop.set()
407
+ raise MessengerReaderConfigError(
408
+ f"Fatal NATS error on {self.subject}: {e.error}"
409
+ ) from e.error
387
410
  match self.error_behavior:
388
411
  case 'RAISE':
389
412
  log.error(st.fmt(f"raising read_next error: {e.error}"))
File without changes
File without changes
File without changes