nucliadb-utils 6.4.0.post4276__py3-none-any.whl → 6.4.0.post4283__py3-none-any.whl

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.
nucliadb_utils/helpers.py CHANGED
@@ -17,7 +17,13 @@
17
17
  # You should have received a copy of the GNU Affero General Public License
18
18
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
  #
20
- from typing import AsyncGenerator
20
+ import asyncio
21
+ import logging
22
+ from typing import AsyncGenerator, Awaitable, Callable
23
+
24
+ from nucliadb_telemetry.errors import capture_exception
25
+
26
+ logger = logging.getLogger(__name__)
21
27
 
22
28
 
23
29
  async def async_gen_lookahead(
@@ -44,3 +50,54 @@ async def async_gen_lookahead(
44
50
  # Yield the last chunk if there is one
45
51
  if buffered_chunk is not None:
46
52
  yield buffered_chunk, True
53
+
54
+
55
+ class MessageProgressUpdater:
56
+ """
57
+ Context manager to send progress updates to NATS.
58
+
59
+ This should allow lower ack_wait time settings without causing
60
+ messages to be redelivered.
61
+ """
62
+
63
+ _task: asyncio.Task
64
+
65
+ def __init__(self, seqid: str, cb: Callable[[], Awaitable[bool]], timeout: float):
66
+ self.seqid = seqid
67
+ self.cb = cb
68
+ self.timeout = timeout
69
+
70
+ def start(self):
71
+ task_name = f"MessageProgressUpdater: {id(self)} (seqid={self.seqid})"
72
+ self._task = asyncio.create_task(self._progress(), name=task_name)
73
+
74
+ async def end(self):
75
+ self._task.cancel()
76
+ try:
77
+ await self._task
78
+ except asyncio.CancelledError: # pragma: no cover
79
+ logger.info("MessageProgressUpdater cancelled")
80
+ pass
81
+ except Exception as exc: # pragma: no cover
82
+ capture_exception(exc)
83
+ logger.exception("Error in MessageProgressUpdater")
84
+ pass
85
+
86
+ async def __aenter__(self):
87
+ self.start()
88
+ return self
89
+
90
+ async def __aexit__(self, exc_type, exc_value, traceback):
91
+ await self.end()
92
+
93
+ async def _progress(self):
94
+ while True:
95
+ try:
96
+ await asyncio.sleep(self.timeout)
97
+ done = await self.cb()
98
+ if done: # all done, do not mark with in_progress
99
+ return
100
+ except (RuntimeError, asyncio.CancelledError):
101
+ return
102
+ except Exception: # pragma: no cover
103
+ logger.exception("Error sending task progress to NATS")
nucliadb_utils/nats.py CHANGED
@@ -28,17 +28,17 @@ import nats
28
28
  import nats.errors
29
29
  import nats.js.api
30
30
  from nats.aio.client import Client as NATSClient
31
- from nats.aio.client import Msg
31
+ from nats.aio.msg import Msg
32
32
  from nats.aio.subscription import Subscription
33
33
  from nats.js.client import JetStreamContext
34
34
 
35
- from nucliadb_telemetry.errors import capture_exception
36
35
  from nucliadb_telemetry.jetstream import (
37
36
  JetStreamContextTelemetry,
38
37
  NatsClientTelemetry,
39
38
  get_traced_nats_client,
40
39
  )
41
40
  from nucliadb_telemetry.metrics import Counter
41
+ from nucliadb_utils.helpers import MessageProgressUpdater
42
42
 
43
43
  logger = logging.getLogger(__name__)
44
44
 
@@ -47,7 +47,7 @@ logger = logging.getLogger(__name__)
47
47
  from nucliadb_telemetry.jetstream import get_traced_jetstream # noqa
48
48
 
49
49
 
50
- class MessageProgressUpdater:
50
+ class NatsMessageProgressUpdater(MessageProgressUpdater):
51
51
  """
52
52
  Context manager to send progress updates to NATS.
53
53
 
@@ -55,47 +55,15 @@ class MessageProgressUpdater:
55
55
  messages to be redelivered.
56
56
  """
57
57
 
58
- _task: asyncio.Task
59
-
60
58
  def __init__(self, msg: Msg, timeout: float):
61
- self.msg = msg
62
- self.timeout = timeout
63
-
64
- def start(self):
65
- seqid = self.msg.reply.split(".")[5]
66
- task_name = f"MessageProgressUpdater: {id(self)} (seqid={seqid})"
67
- self._task = asyncio.create_task(self._progress(), name=task_name)
68
-
69
- async def end(self):
70
- self._task.cancel()
71
- try:
72
- await self._task
73
- except asyncio.CancelledError: # pragma: no cover
74
- logger.info("MessageProgressUpdater cancelled")
75
- pass
76
- except Exception as exc: # pragma: no cover
77
- capture_exception(exc)
78
- logger.exception("Error in MessageProgressUpdater")
79
- pass
80
-
81
- async def __aenter__(self):
82
- self.start()
83
- return self
84
-
85
- async def __aexit__(self, exc_type, exc_value, traceback):
86
- await self.end()
87
-
88
- async def _progress(self):
89
- while True:
90
- try:
91
- await asyncio.sleep(self.timeout)
92
- if self.msg._ackd: # all done, do not mark with in_progress
93
- return
94
- await self.msg.in_progress()
95
- except (RuntimeError, asyncio.CancelledError):
96
- return
97
- except Exception: # pragma: no cover
98
- logger.exception("Error sending task progress to NATS")
59
+ async def update_msg() -> bool:
60
+ if msg._ackd: # all done, do not mark with in_progress
61
+ return True
62
+ await msg.in_progress()
63
+ return False
64
+
65
+ seqid = msg.reply.split(".")[5]
66
+ super().__init__(seqid, update_msg, timeout)
99
67
 
100
68
 
101
69
  class NatsConnectionManager:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nucliadb_utils
3
- Version: 6.4.0.post4276
3
+ Version: 6.4.0.post4283
4
4
  Summary: NucliaDB util library
5
5
  Author-email: Nuclia <nucliadb@nuclia.com>
6
6
  License: AGPL
@@ -27,8 +27,8 @@ Requires-Dist: nats-py[nkeys]>=2.6.0
27
27
  Requires-Dist: PyNaCl
28
28
  Requires-Dist: pyjwt>=2.4.0
29
29
  Requires-Dist: mrflagly>=0.2.9
30
- Requires-Dist: nucliadb-protos>=6.4.0.post4276
31
- Requires-Dist: nucliadb-telemetry>=6.4.0.post4276
30
+ Requires-Dist: nucliadb-protos>=6.4.0.post4283
31
+ Requires-Dist: nucliadb-telemetry>=6.4.0.post4283
32
32
  Provides-Extra: cache
33
33
  Requires-Dist: redis>=4.3.4; extra == "cache"
34
34
  Requires-Dist: orjson>=3.6.7; extra == "cache"
@@ -6,8 +6,8 @@ nucliadb_utils/debug.py,sha256=Q56Nx9Dp7V2ae3CU2H0ztaZcHTJXdlflPLKLeOPZ170,2436
6
6
  nucliadb_utils/exceptions.py,sha256=y_3wk77WLVUtdo-5FtbBsdSkCtK_DsJkdWb5BoPn3qo,1094
7
7
  nucliadb_utils/featureflagging.py,sha256=YxDiXzWuiDlHtqgeTVeyakmbAdzBePzJpgJv53ELbmI,2259
8
8
  nucliadb_utils/grpc.py,sha256=apu0uePnkGHCAT7GRQ9YZfRYyFj26kJ440i8jitbM3U,3314
9
- nucliadb_utils/helpers.py,sha256=nPw8yod3hP-pxq80VF8QC36s7ygSg0dBUdfI-LatvCs,1600
10
- nucliadb_utils/nats.py,sha256=uMs5dTaAplBuj0D0NFFmXGmobrnl4N3FzhCMa-YsnFc,16204
9
+ nucliadb_utils/helpers.py,sha256=eed7_E1MKh9eW3CpqOXka3OvLw5C9eJGC_R-1MPYdfY,3336
10
+ nucliadb_utils/nats.py,sha256=On-2TQRD7U7SVZjhoJWONPH18CUyrWB2Pz-Ax5ji3MA,15191
11
11
  nucliadb_utils/partition.py,sha256=jBgy4Hu5Iwn4gjbPPcthSykwf-qNx-GcLAIwbzPd1d0,1157
12
12
  nucliadb_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  nucliadb_utils/run.py,sha256=Es0_Bu5Yc-LWczvwL6gzWqSwC85RjDCk-0oFQAJi9g4,1827
@@ -57,7 +57,7 @@ nucliadb_utils/tests/gcs.py,sha256=MBMzn_UHU5SU6iILuCsB5zU4umhNcaCw_MKrxZhwvOc,4
57
57
  nucliadb_utils/tests/local.py,sha256=cxIfPrKuqs5Ef0nbrVYQQAH2mwc4E0iD9bC2sWegS-c,1934
58
58
  nucliadb_utils/tests/nats.py,sha256=RWHjwqq5esuO7OFbP24yYX1cXnpPLcWJwDUdmwCpH28,1897
59
59
  nucliadb_utils/tests/s3.py,sha256=DACUh3HvgH3BchKFZ9R7RFUzsrg3v9A-cxTcXx4nmvA,3734
60
- nucliadb_utils-6.4.0.post4276.dist-info/METADATA,sha256=EHKOe5MxYezmQuO_4PEgq3lzIGxLX3AfZs1LpllDTQ4,2156
61
- nucliadb_utils-6.4.0.post4276.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
62
- nucliadb_utils-6.4.0.post4276.dist-info/top_level.txt,sha256=fE3vJtALTfgh7bcAWcNhcfXkNPp_eVVpbKK-2IYua3E,15
63
- nucliadb_utils-6.4.0.post4276.dist-info/RECORD,,
60
+ nucliadb_utils-6.4.0.post4283.dist-info/METADATA,sha256=SbycFCOY8JRYEUVzhwyDTQxNYEkVTh3s8Z-mHyQabZU,2156
61
+ nucliadb_utils-6.4.0.post4283.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
62
+ nucliadb_utils-6.4.0.post4283.dist-info/top_level.txt,sha256=fE3vJtALTfgh7bcAWcNhcfXkNPp_eVVpbKK-2IYua3E,15
63
+ nucliadb_utils-6.4.0.post4283.dist-info/RECORD,,