log-foundry 0.10.2.dev87__tar.gz → 0.10.2.dev89__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.
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/PKG-INFO +1 -1
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/pyproject.toml +1 -1
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/_retry.py +26 -2
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/kafka.py +5 -5
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/nats.py +102 -10
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/LICENSE +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/README.md +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/__init__.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/_diag.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/_fork.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/_lifecycle.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/api.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/config.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/console.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/context.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/decorator.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/ids.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/model.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/py.typed +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/results.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sanitize.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/__init__.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/_batch.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/_chunk.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/_socket.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/_time.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/base.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/callback.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/clickhouse.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/datadog.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/elasticsearch.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/eventhubs.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/file.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/filtering.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/firehose.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/honeycomb.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/http.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/kinesis.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/logging_sink.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/logstash.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/loki.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/memory.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/mongodb.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/multi.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/newrelic.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/null.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/postgres.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/pubsub.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/rabbitmq.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/redis.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/sentry.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/sns.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/splunk.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/sqlite.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/sqs.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/stdout.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/syslog.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/transform.py +0 -0
- {log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/worker.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Shared
|
|
1
|
+
"""Shared bounding of the sinks' waits and timeouts (SPEC-027, SPEC-047)."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
10
|
import threading
|
|
11
11
|
|
|
12
|
-
__all__ = ["MAX_WAIT", "clamp_server_delay", "wait"]
|
|
12
|
+
__all__ = ["MAX_WAIT", "clamp_server_delay", "usable_timeout", "wait"]
|
|
13
13
|
|
|
14
14
|
MAX_WAIT = 86_400.0
|
|
15
15
|
"""Hard ceiling on any single wait, in seconds — a day.
|
|
@@ -87,3 +87,27 @@ def clamp_server_delay(value: float | None, ceiling: float) -> float | None:
|
|
|
87
87
|
if not (ceiling > 0):
|
|
88
88
|
return None
|
|
89
89
|
return min(value, ceiling)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def usable_timeout(value: float, default: float) -> float:
|
|
93
|
+
"""Returns a timeout that actually bounds something, or the caller's default (SPEC-047).
|
|
94
|
+
|
|
95
|
+
``0`` switches a bounded wait off entirely and ``inf`` restores the unbounded one the bound
|
|
96
|
+
exists to remove, so neither is accepted. The test is ``not (0 < value < inf)`` rather than a
|
|
97
|
+
pair of comparisons, because ``NaN`` compares ``False`` to everything and would otherwise slip
|
|
98
|
+
through — :func:`clamp_server_delay`'s reasoning for ``Retry-After``, applied to a value the
|
|
99
|
+
caller supplies rather than one a destination does.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
value: The caller's timeout.
|
|
103
|
+
default: The fallback, passed in rather than named here because each sink's default is its
|
|
104
|
+
own — ``KafkaSink``'s flush and ``NATSSink``'s publish budget are unrelated numbers, and a
|
|
105
|
+
constant baked in here would silently give one sink the other's.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
The value if it bounds anything, else the default.
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
None.
|
|
112
|
+
"""
|
|
113
|
+
return value if 0 < value < float("inf") else default
|
|
@@ -7,6 +7,7 @@ import threading
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
9
|
from log_foundry import _diag
|
|
10
|
+
from log_foundry.sinks._retry import usable_timeout
|
|
10
11
|
from log_foundry.sinks.base import SinkDeliveryError, SinkLosses
|
|
11
12
|
|
|
12
13
|
__all__ = ["KafkaSink"]
|
|
@@ -16,10 +17,9 @@ def _usable_timeout(value: float) -> float:
|
|
|
16
17
|
"""Returns a flush timeout that is actually a bound, or the default.
|
|
17
18
|
|
|
18
19
|
``0`` is the value that switched this sink's exit delivery off, and ``inf`` is the unbounded
|
|
19
|
-
wait FR-006 exists to remove, so neither is accepted from a caller. The
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
``Retry-After``).
|
|
20
|
+
wait FR-006 exists to remove, so neither is accepted from a caller. The rule itself lives in
|
|
21
|
+
:func:`~log_foundry.sinks._retry.usable_timeout`, shared with ``NATSSink``'s publish budget
|
|
22
|
+
since SPEC-047; this wrapper binds it to :data:`DEFAULT_FLUSH_TIMEOUT`.
|
|
23
23
|
|
|
24
24
|
Args:
|
|
25
25
|
value: The caller's timeout.
|
|
@@ -30,7 +30,7 @@ def _usable_timeout(value: float) -> float:
|
|
|
30
30
|
Raises:
|
|
31
31
|
None.
|
|
32
32
|
"""
|
|
33
|
-
return value
|
|
33
|
+
return usable_timeout(value, DEFAULT_FLUSH_TIMEOUT)
|
|
34
34
|
|
|
35
35
|
DEFAULT_FLUSH_TIMEOUT = 10.0
|
|
36
36
|
"""Seconds :meth:`KafkaSink.close` waits for the producer to drain (SPEC-038 FR-006).
|
|
@@ -5,13 +5,50 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import json
|
|
7
7
|
import threading
|
|
8
|
+
import time
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
10
11
|
from log_foundry import _diag
|
|
12
|
+
from log_foundry.sinks._retry import usable_timeout
|
|
11
13
|
from log_foundry.sinks.base import SinkDeliveryError, SinkLosses
|
|
12
14
|
|
|
13
15
|
__all__ = ["NATSSink"]
|
|
14
16
|
|
|
17
|
+
DEFAULT_PUBLISH_TIMEOUT = 10.0
|
|
18
|
+
"""Seconds one whole :meth:`NATSSink.emit` may spend publishing (SPEC-047 FR-001).
|
|
19
|
+
|
|
20
|
+
A budget for the **batch**, not for an event. Under JetStream each publish awaits an ack bounded by
|
|
21
|
+
the driver's own timeout, and applying that per item is ``n x timeout``, which is not a bound --
|
|
22
|
+
measured, five events against a stalled server cost 25.01 s, and ``Worker._final_drain`` hands the
|
|
23
|
+
process's exit backlog over as a single batch (SPEC-038 measured 5,980 events).
|
|
24
|
+
|
|
25
|
+
It is spent inside ``_lifecycle.DEFAULT_SHUTDOWN_TIMEOUT`` (30.0): ``Worker.shutdown`` joins the
|
|
26
|
+
drain thread against that deadline and ``_final_drain``'s single emit runs on that thread, and an
|
|
27
|
+
expired join leaves the sink **open** by SPEC-027 FR-004, so ``close()`` never drains the client's
|
|
28
|
+
outbound buffer.
|
|
29
|
+
|
|
30
|
+
**It does not fit inside that join, and the arithmetic is stated rather than assumed.**
|
|
31
|
+
``Worker._emit`` retries a failing batch ``max_retries + 1`` times -- four at the default -- and its
|
|
32
|
+
inter-attempt wait returns immediately once the stop event is set, which it is for the whole of the
|
|
33
|
+
exit drain. This deadline deliberately does not consult that event (a shutdown shortens a wait and
|
|
34
|
+
never skips work), so the exit drain's worst case is ``(max_retries + 1) x publish_timeout``. Ten is
|
|
35
|
+
chosen on the size of the improvement rather than on fitting the sequence inside the join: the same
|
|
36
|
+
path is *unbounded* today, 8.3 hours for a 5,980-event backlog at 5 s an event. A caller who needs
|
|
37
|
+
the whole sequence to fit lowers this to 7.0 or below. Recorded as an open item in
|
|
38
|
+
``architecture.md`` section 12, since closing it means bounding the worker's retry of an
|
|
39
|
+
already-bounded batch -- every sink's question rather than this sink's.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
DEFAULT_ACK_TIMEOUT = 5.0
|
|
43
|
+
"""Ceiling on any one JetStream publish's ack wait, in seconds (SPEC-047 FR-001).
|
|
44
|
+
|
|
45
|
+
A constant of this module's own rather than a value read from the driver: the sink builds its
|
|
46
|
+
context with a bare ``self._client.jetstream()``, so ``JetStreamContext``'s ``timeout`` is its
|
|
47
|
+
constructor default and is not readable back off the object. It mirrors that default, and every
|
|
48
|
+
publish is given ``min(DEFAULT_ACK_TIMEOUT, remaining budget)`` -- so a divergence can only ever
|
|
49
|
+
make the per-publish timeout smaller than the driver would have used, never larger.
|
|
50
|
+
"""
|
|
51
|
+
|
|
15
52
|
|
|
16
53
|
class NATSSink:
|
|
17
54
|
"""A :class:`~log_foundry.sinks.base.Sink` that publishes events to a NATS subject.
|
|
@@ -22,12 +59,23 @@ class NATSSink:
|
|
|
22
59
|
handed off. With JetStream enabled it publishes through JetStream for durable
|
|
23
60
|
acknowledgement.
|
|
24
61
|
|
|
25
|
-
**Retry and the worst-case delay** (SPEC-041 FR-004). This sink adds no retry
|
|
26
|
-
none: a core ``publish()`` writes into the client's outbound buffer and returns
|
|
27
|
-
waiting — measured at 0.00 s for fifty publishes — so it never holds the worker's
|
|
28
|
-
drain thread and there is no backoff for a shutdown to cut short. SPEC-027's guarantee
|
|
29
|
-
because there is no wait, not because a wait is bounded.
|
|
30
|
-
|
|
62
|
+
**Retry and the worst-case delay** (SPEC-041 FR-004, SPEC-047 FR-001). This sink adds no retry
|
|
63
|
+
loop and needs none: a core ``publish()`` writes into the client's outbound buffer and returns
|
|
64
|
+
without waiting — measured at 0.00 s for fifty publishes — so it never holds the worker's
|
|
65
|
+
single drain thread and there is no backoff for a shutdown to cut short. SPEC-027's guarantee
|
|
66
|
+
is met because there is no wait, not because a wait is bounded.
|
|
67
|
+
|
|
68
|
+
> ~~Under JetStream ``publish()`` awaits an ack bounded by the driver's own timeout (5 s by
|
|
69
|
+
> default) and does not retry.~~ **Superseded by SPEC-047 FR-001.** True per *event* and false
|
|
70
|
+
> per *batch*: the awaits are sequential and nothing bounded how many there were, so the cost
|
|
71
|
+
> was ``n x 5 s`` on the drain thread — measured at 25.01 s for five events against a stalled
|
|
72
|
+
> server, and ``Worker._final_drain`` hands the exit backlog over as one batch. One
|
|
73
|
+
> :data:`DEFAULT_PUBLISH_TIMEOUT` now bounds the whole :meth:`emit`.
|
|
74
|
+
|
|
75
|
+
The worst case is therefore ``publish_timeout`` per emit, plus one in-flight ack — and across
|
|
76
|
+
the exit drain ``(max_retries + 1) x publish_timeout``, since ``Worker._emit`` retries a failing
|
|
77
|
+
batch and its inter-attempt wait returns immediately during a shutdown. That exceeds
|
|
78
|
+
``shutdown()``'s join at the defaults and is recorded in ``architecture.md`` section 12.
|
|
31
79
|
|
|
32
80
|
**A disconnected client is reported, not absorbed** (FR-004 AC-5). That non-blocking publish
|
|
33
81
|
is exactly what made this sink report success for events that had not left the process: with
|
|
@@ -55,6 +103,7 @@ class NATSSink:
|
|
|
55
103
|
client: Any = None,
|
|
56
104
|
jetstream: bool = False,
|
|
57
105
|
servers: str | None = None,
|
|
106
|
+
publish_timeout: float = DEFAULT_PUBLISH_TIMEOUT,
|
|
58
107
|
) -> None:
|
|
59
108
|
"""Binds the sink to a subject and connects if no client was injected.
|
|
60
109
|
|
|
@@ -63,6 +112,10 @@ class NATSSink:
|
|
|
63
112
|
client: A ``nats-py``-shaped client to borrow, or ``None`` to connect one.
|
|
64
113
|
jetstream: Whether to publish through JetStream.
|
|
65
114
|
servers: The server URL used when connecting.
|
|
115
|
+
publish_timeout: Seconds one whole :meth:`emit` may spend, floored by
|
|
116
|
+
:func:`~log_foundry.sinks._retry.usable_timeout` as ``KafkaSink`` floors its flush
|
|
117
|
+
(SPEC-047 FR-001). It applies to an injected ``client=`` too: it is this sink's own
|
|
118
|
+
bound over its own loop, not a request made of the driver at connect time.
|
|
66
119
|
|
|
67
120
|
Returns:
|
|
68
121
|
None.
|
|
@@ -73,6 +126,7 @@ class NATSSink:
|
|
|
73
126
|
"""
|
|
74
127
|
self._subject = subject
|
|
75
128
|
self._jetstream = jetstream
|
|
129
|
+
self.publish_timeout = usable_timeout(publish_timeout, DEFAULT_PUBLISH_TIMEOUT)
|
|
76
130
|
self._loop = asyncio.new_event_loop()
|
|
77
131
|
self.failed = 0
|
|
78
132
|
self._counter_lock = threading.Lock()
|
|
@@ -179,10 +233,27 @@ class NATSSink:
|
|
|
179
233
|
self._loop.close()
|
|
180
234
|
|
|
181
235
|
async def _publish_all(self, batch: list[dict[str, object]]) -> None:
|
|
182
|
-
"""Publishes each event
|
|
236
|
+
"""Publishes each event under one deadline for the whole batch (SPEC-047 FR-001).
|
|
183
237
|
|
|
184
238
|
Per-event isolation stays because a partial batch must not be retried wholesale: the
|
|
185
|
-
events that published would be delivered twice.
|
|
239
|
+
events that published would be delivered twice. What changes is that the *batch* is
|
|
240
|
+
bounded rather than each event in it — applying the driver's ack timeout per item is
|
|
241
|
+
``n x timeout``, and ``Worker._final_drain`` hands the exit backlog over as one batch.
|
|
242
|
+
|
|
243
|
+
The two paths take the bound differently because the driver offers different handles. A
|
|
244
|
+
JetStream publish accepts a ``timeout`` and is given ``min(DEFAULT_ACK_TIMEOUT,
|
|
245
|
+
remaining)`` — never the bare remainder, which would hand the first event of a fresh
|
|
246
|
+
budget a longer ack wait than the driver's own default. A core publish accepts none and
|
|
247
|
+
writes into the client's outbound buffer without waiting, so the deadline is checked
|
|
248
|
+
between events, which is all there is to check.
|
|
249
|
+
|
|
250
|
+
Two populations are counted by different rules. An event whose publish **raised** is a
|
|
251
|
+
driver failure and is counted here exactly as before this spec. An event **never
|
|
252
|
+
attempted** because the budget expired is counted only when this returns: a raise sends
|
|
253
|
+
the whole batch back to ``Worker._emit``, which retries it, so booking the remainder there
|
|
254
|
+
would report a loss that has not happened — the rule
|
|
255
|
+
:meth:`~log_foundry.sinks.kafka.KafkaSink.flush` already applies to its own queued
|
|
256
|
+
remainder.
|
|
186
257
|
|
|
187
258
|
Args:
|
|
188
259
|
batch: The events to publish.
|
|
@@ -194,18 +265,39 @@ class NATSSink:
|
|
|
194
265
|
SinkDeliveryError: When none of them landed (SPEC-026 FR-001).
|
|
195
266
|
"""
|
|
196
267
|
target = self._client.jetstream() if self._jetstream else self._client
|
|
268
|
+
deadline = time.monotonic() + self.publish_timeout
|
|
197
269
|
published = 0
|
|
270
|
+
attempted = 0
|
|
198
271
|
for event in batch:
|
|
272
|
+
remaining = deadline - time.monotonic()
|
|
273
|
+
if remaining <= 0:
|
|
274
|
+
break
|
|
275
|
+
attempted += 1
|
|
199
276
|
try:
|
|
200
|
-
|
|
277
|
+
payload = json.dumps(event).encode("utf-8")
|
|
278
|
+
if self._jetstream:
|
|
279
|
+
await target.publish(
|
|
280
|
+
self._subject, payload, timeout=min(DEFAULT_ACK_TIMEOUT, remaining)
|
|
281
|
+
)
|
|
282
|
+
else:
|
|
283
|
+
await target.publish(self._subject, payload)
|
|
201
284
|
except Exception as err:
|
|
202
285
|
with self._counter_lock:
|
|
203
286
|
self.failed += 1
|
|
204
287
|
_diag.lost("event", 1, f"NATSSink publish, {type(err).__name__}")
|
|
205
288
|
else:
|
|
206
289
|
published += 1
|
|
290
|
+
unattempted = len(batch) - attempted
|
|
207
291
|
if batch and not published:
|
|
208
|
-
raise SinkDeliveryError(
|
|
292
|
+
raise SinkDeliveryError(
|
|
293
|
+
f"NATSSink published none of {len(batch)} event(s)"
|
|
294
|
+
+ (f", {unattempted} not attempted within {self.publish_timeout}s" if unattempted
|
|
295
|
+
else "")
|
|
296
|
+
)
|
|
297
|
+
if unattempted:
|
|
298
|
+
with self._counter_lock:
|
|
299
|
+
self.failed += unattempted
|
|
300
|
+
_diag.lost("event", unattempted, f"NATSSink publish_timeout {self.publish_timeout}s")
|
|
209
301
|
|
|
210
302
|
def flush(self) -> None:
|
|
211
303
|
"""Pushes the client's outbound buffer onto the wire without closing (SPEC-036 FR-002).
|
|
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
|
{log_foundry-0.10.2.dev87 → log_foundry-0.10.2.dev89}/src/log_foundry/sinks/elasticsearch.py
RENAMED
|
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
|