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.
- {serverish-2.0.3 → serverish-2.0.5}/PKG-INFO +1 -1
- {serverish-2.0.3 → serverish-2.0.5}/pyproject.toml +1 -1
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/exceptions.py +9 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_callback_sub.py +9 -3
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_reader.py +24 -1
- {serverish-2.0.3 → serverish-2.0.5}/LICENSE +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/README.md +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/__init__.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/__init__.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/asyncio_util_functions.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/collector.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/datetime.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/fifoset.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/hasstatuses.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/idmanger.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/iterators.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/manageable.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/singleton.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/status.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/base/task_manager.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/__init__.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/connection.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/connection_jets.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/connection/connection_nats.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/__init__.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/live_document.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/logging.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/messenger.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_cmd_pub.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_cmd_sub.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_core_pub.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_core_read.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_core_sub.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_document_read.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_journal_pub.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_journal_read.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_progress_pub.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_progress_read.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_publisher.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_rpc_req.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_rpc_resp.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_single_pub.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msg_single_read.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/messenger/msgvalidator.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/__init__.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/bridge.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/factory.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/monitored.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/monitoring/monitored_nats.py +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/config.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/default.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/include/timestamp.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/journal.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/meta.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/program_current_state.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/program_state.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/progress.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/schema/telemetry.schema.json +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/services/TODO.txt +0 -0
- {serverish-2.0.3 → serverish-2.0.5}/serverish/slog.py +0 -0
|
@@ -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
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|