nucliadb-utils 6.1.0.post2473__py3-none-any.whl → 6.1.0.post2476__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/const.py +3 -2
- nucliadb_utils/featureflagging.py +4 -0
- nucliadb_utils/nats.py +98 -8
- nucliadb_utils/tests/gcs.py +1 -1
- {nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/METADATA +3 -3
- {nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/RECORD +9 -9
- {nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/WHEEL +0 -0
- {nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/top_level.txt +0 -0
- {nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/zip-safe +0 -0
nucliadb_utils/const.py
CHANGED
@@ -30,7 +30,7 @@ class Streams:
|
|
30
30
|
|
31
31
|
name = "nucliadb"
|
32
32
|
subject = "ndb.consumer.{partition}"
|
33
|
-
group = "nucliadb-{partition}"
|
33
|
+
group = "nucliadb-pull-{partition}"
|
34
34
|
|
35
35
|
class INGEST_PROCESSED:
|
36
36
|
"""
|
@@ -40,7 +40,7 @@ class Streams:
|
|
40
40
|
|
41
41
|
name = "nucliadb"
|
42
42
|
subject = "ndb.consumer.processed"
|
43
|
-
group = "nucliadb-processed"
|
43
|
+
group = "nucliadb-pull-processed"
|
44
44
|
|
45
45
|
class INDEX:
|
46
46
|
"""
|
@@ -80,3 +80,4 @@ class Features:
|
|
80
80
|
LOG_REQUEST_PAYLOADS = "nucliadb_log_request_payloads"
|
81
81
|
IGNORE_EXTRACTED_IN_SEARCH = "nucliadb_ignore_extracted_in_search"
|
82
82
|
NIDX_READS = "nucliadb_nidx_reads"
|
83
|
+
PULL_PROCESSED_CONSUMERS_DEPLOYED = "nucliadb_pull_processed_consumers_deployed"
|
nucliadb_utils/nats.py
CHANGED
@@ -104,6 +104,11 @@ class MessageProgressUpdater:
|
|
104
104
|
class NatsConnectionManager:
|
105
105
|
_nc: NATSClient
|
106
106
|
_subscriptions: list[tuple[Subscription, Callable[[], Awaitable[None]]]]
|
107
|
+
_pull_subscriptions: list[
|
108
|
+
tuple[
|
109
|
+
JetStreamContext.PullSubscription, asyncio.Task, Callable[[], Awaitable[None]], asyncio.Event
|
110
|
+
]
|
111
|
+
]
|
107
112
|
_unhealthy_timeout = 10 # needs to be unhealth for 10 seconds to be unhealthy and force exit
|
108
113
|
|
109
114
|
def __init__(
|
@@ -117,6 +122,7 @@ class NatsConnectionManager:
|
|
117
122
|
self._nats_servers = nats_servers
|
118
123
|
self._nats_creds = nats_creds
|
119
124
|
self._subscriptions = []
|
125
|
+
self._pull_subscriptions = []
|
120
126
|
self._lock = asyncio.Lock()
|
121
127
|
self._healthy = True
|
122
128
|
self._last_unhealthy: Optional[float] = None
|
@@ -155,11 +161,26 @@ class NatsConnectionManager:
|
|
155
161
|
|
156
162
|
async def finalize(self):
|
157
163
|
async with self._lock:
|
164
|
+
# Finalize push subscriptions
|
158
165
|
for sub, _ in self._subscriptions:
|
159
166
|
try:
|
160
167
|
await sub.drain()
|
161
168
|
except nats.errors.ConnectionClosedError: # pragma: no cover
|
162
169
|
pass
|
170
|
+
self._subscriptions = []
|
171
|
+
|
172
|
+
# Finalize pull subscriptions
|
173
|
+
for pull_sub, task, _, cancelled in self._pull_subscriptions:
|
174
|
+
cancelled.set()
|
175
|
+
task.cancel()
|
176
|
+
try:
|
177
|
+
await task
|
178
|
+
except asyncio.CancelledError:
|
179
|
+
pass
|
180
|
+
await pull_sub.unsubscribe()
|
181
|
+
self._pull_subscriptions = []
|
182
|
+
|
183
|
+
# Close the connection
|
163
184
|
try:
|
164
185
|
await asyncio.wait_for(self._nc.drain(), timeout=1)
|
165
186
|
except (
|
@@ -168,7 +189,6 @@ class NatsConnectionManager:
|
|
168
189
|
): # pragma: no cover
|
169
190
|
pass
|
170
191
|
await self._nc.close()
|
171
|
-
self._subscriptions = []
|
172
192
|
|
173
193
|
async def disconnected_cb(self) -> None:
|
174
194
|
logger.info("Disconnected from NATS!")
|
@@ -193,6 +213,26 @@ class NatsConnectionManager:
|
|
193
213
|
# should force exit here to restart the service
|
194
214
|
self._healthy = False
|
195
215
|
raise
|
216
|
+
|
217
|
+
existing_pull_subs = self._pull_subscriptions
|
218
|
+
self._pull_subscriptions = []
|
219
|
+
for pull_sub, task, recon_callback, cancelled in existing_pull_subs:
|
220
|
+
cancelled.set()
|
221
|
+
task.cancel()
|
222
|
+
try:
|
223
|
+
await task
|
224
|
+
except asyncio.CancelledError:
|
225
|
+
pass
|
226
|
+
try:
|
227
|
+
await pull_sub.unsubscribe()
|
228
|
+
await recon_callback()
|
229
|
+
except Exception:
|
230
|
+
logger.exception(
|
231
|
+
f"Error resubscribing to pull subscription on {self._nc.connected_url.netloc}"
|
232
|
+
)
|
233
|
+
# should force exit here to restart the service
|
234
|
+
self._healthy = False
|
235
|
+
raise
|
196
236
|
self._healthy = True
|
197
237
|
self._last_unhealthy = None # reset the last unhealthy time
|
198
238
|
|
@@ -236,17 +276,67 @@ class NatsConnectionManager:
|
|
236
276
|
|
237
277
|
return sub
|
238
278
|
|
239
|
-
async def
|
279
|
+
async def pull_subscribe(
|
280
|
+
self,
|
281
|
+
*,
|
282
|
+
subject: str,
|
283
|
+
stream: str,
|
284
|
+
cb: Callable[[Msg], Awaitable[None]],
|
285
|
+
subscription_lost_cb: Callable[[], Awaitable[None]],
|
286
|
+
durable: Optional[str] = None,
|
287
|
+
config: Optional[nats.js.api.ConsumerConfig] = None,
|
288
|
+
) -> JetStreamContext.PullSubscription:
|
289
|
+
psub = await self.js.pull_subscribe(
|
290
|
+
subject,
|
291
|
+
durable=durable, # type: ignore
|
292
|
+
stream=stream,
|
293
|
+
config=config, # type: ignore
|
294
|
+
)
|
295
|
+
|
296
|
+
cancelled = asyncio.Event()
|
297
|
+
|
298
|
+
async def consume(psub: JetStreamContext.PullSubscription, subject: str):
|
299
|
+
while True:
|
300
|
+
if cancelled.is_set():
|
301
|
+
break
|
302
|
+
try:
|
303
|
+
messages = await psub.fetch(batch=1)
|
304
|
+
for message in messages:
|
305
|
+
await cb(message)
|
306
|
+
except asyncio.CancelledError:
|
307
|
+
# Handle task cancellation
|
308
|
+
logger.info("Pull subscription consume task cancelled", extra={"subject": subject})
|
309
|
+
break
|
310
|
+
except TimeoutError:
|
311
|
+
pass
|
312
|
+
except Exception:
|
313
|
+
logger.exception("Error in pull_subscribe task", extra={"subject": subject})
|
314
|
+
|
315
|
+
task = asyncio.create_task(consume(psub, subject), name=f"pull_subscribe_{subject}")
|
316
|
+
self._pull_subscriptions.append((psub, task, subscription_lost_cb, cancelled))
|
317
|
+
return psub
|
318
|
+
|
319
|
+
async def _remove_subscription(
|
320
|
+
self, subscription: Union[Subscription, JetStreamContext.PullSubscription]
|
321
|
+
):
|
240
322
|
async with self._lock:
|
241
|
-
sub_index = None
|
242
323
|
for index, (sub, _) in enumerate(self._subscriptions):
|
243
324
|
if sub is not subscription:
|
244
325
|
continue
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
326
|
+
self._subscriptions.pop(index)
|
327
|
+
return
|
328
|
+
for index, (psub, task, _, cancelled) in enumerate(self._pull_subscriptions):
|
329
|
+
if psub is not subscription:
|
330
|
+
continue
|
331
|
+
self._pull_subscriptions.pop(index)
|
332
|
+
cancelled.set()
|
333
|
+
task.cancel()
|
334
|
+
try:
|
335
|
+
await task
|
336
|
+
except asyncio.CancelledError:
|
337
|
+
pass
|
338
|
+
return
|
249
339
|
|
250
|
-
async def unsubscribe(self, subscription: Subscription):
|
340
|
+
async def unsubscribe(self, subscription: Union[Subscription, JetStreamContext.PullSubscription]):
|
251
341
|
await subscription.unsubscribe()
|
252
342
|
await self._remove_subscription(subscription)
|
nucliadb_utils/tests/gcs.py
CHANGED
{nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nucliadb_utils
|
3
|
-
Version: 6.1.0.
|
3
|
+
Version: 6.1.0.post2476
|
4
4
|
Home-page: https://nuclia.com
|
5
5
|
License: BSD
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
@@ -24,8 +24,8 @@ Requires-Dist: PyNaCl
|
|
24
24
|
Requires-Dist: pyjwt>=2.4.0
|
25
25
|
Requires-Dist: memorylru>=1.1.2
|
26
26
|
Requires-Dist: mrflagly>=0.2.9
|
27
|
-
Requires-Dist: nucliadb-protos>=6.1.0.
|
28
|
-
Requires-Dist: nucliadb-telemetry>=6.1.0.
|
27
|
+
Requires-Dist: nucliadb-protos>=6.1.0.post2476
|
28
|
+
Requires-Dist: nucliadb-telemetry>=6.1.0.post2476
|
29
29
|
Provides-Extra: cache
|
30
30
|
Requires-Dist: redis>=4.3.4; extra == "cache"
|
31
31
|
Requires-Dist: orjson>=3.6.7; extra == "cache"
|
@@ -1,14 +1,14 @@
|
|
1
1
|
nucliadb_utils/__init__.py,sha256=EvBCH1iTODe-AgXm48aj4kVUt_Std3PeL8QnwimR5wI,895
|
2
2
|
nucliadb_utils/asyncio_utils.py,sha256=h8Y-xpcFFRgNzaiIW0eidz7griAQa7ggbNk34-tAt2c,2888
|
3
3
|
nucliadb_utils/authentication.py,sha256=N__d2Ez3JHJv5asYK5TgUcIkKqcAC8ZTLlnfLhfSneM,5837
|
4
|
-
nucliadb_utils/const.py,sha256=
|
4
|
+
nucliadb_utils/const.py,sha256=0zsA5Ys2NQoJECenjX8aSgQGqizqmsUZCcIp87E-61A,2572
|
5
5
|
nucliadb_utils/debug.py,sha256=Q56Nx9Dp7V2ae3CU2H0ztaZcHTJXdlflPLKLeOPZ170,2436
|
6
6
|
nucliadb_utils/exceptions.py,sha256=y_3wk77WLVUtdo-5FtbBsdSkCtK_DsJkdWb5BoPn3qo,1094
|
7
|
-
nucliadb_utils/featureflagging.py,sha256=
|
7
|
+
nucliadb_utils/featureflagging.py,sha256=5J5Je_cZ05f0xnKLvWDMLi3eqKGKAOfR_MItDnAHJj0,3086
|
8
8
|
nucliadb_utils/grpc.py,sha256=apu0uePnkGHCAT7GRQ9YZfRYyFj26kJ440i8jitbM3U,3314
|
9
9
|
nucliadb_utils/helpers.py,sha256=nPw8yod3hP-pxq80VF8QC36s7ygSg0dBUdfI-LatvCs,1600
|
10
10
|
nucliadb_utils/indexing.py,sha256=Luaqcar3CySpdYOFp6Q9Fyr8ZYwhYhaKRHQ_VGL78f8,2318
|
11
|
-
nucliadb_utils/nats.py,sha256=
|
11
|
+
nucliadb_utils/nats.py,sha256=SGBWtP0h3_9Ne6VEfZ2OLnWlEvzfAj63U252FrTITjY,11870
|
12
12
|
nucliadb_utils/partition.py,sha256=jBgy4Hu5Iwn4gjbPPcthSykwf-qNx-GcLAIwbzPd1d0,1157
|
13
13
|
nucliadb_utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
14
|
nucliadb_utils/run.py,sha256=Es0_Bu5Yc-LWczvwL6gzWqSwC85RjDCk-0oFQAJi9g4,1827
|
@@ -54,13 +54,13 @@ nucliadb_utils/tests/__init__.py,sha256=Oo9CAE7B0eW5VHn8sHd6o30SQzOWUhktLPRXdlDO
|
|
54
54
|
nucliadb_utils/tests/asyncbenchmark.py,sha256=x4be2IwCawle9zWgMOJkmwoUwk5p1tv7cLQGmybkEOg,10587
|
55
55
|
nucliadb_utils/tests/azure.py,sha256=Dg-Eb4KVScG-O6P9y-bVQZTAKTNUMQ0i-CKEd9IdrWw,4474
|
56
56
|
nucliadb_utils/tests/fixtures.py,sha256=i0sqPqe5a5JlKGFdaIvOlHYkZ3pHZ2hTIgTsaIB3vSM,3472
|
57
|
-
nucliadb_utils/tests/gcs.py,sha256=
|
57
|
+
nucliadb_utils/tests/gcs.py,sha256=wO4xRhl-_wrddxlGyEktqa_bXHeQarQN-l_A72Tzr9A,4499
|
58
58
|
nucliadb_utils/tests/indexing.py,sha256=YW2QhkhO9Q_8A4kKWJaWSvXvyQ_AiAwY1VylcfVQFxk,1513
|
59
59
|
nucliadb_utils/tests/local.py,sha256=fXIBasrvdaFJM-sw2wk1_oiFzBcm9O10iCyC-OiXwY8,1914
|
60
60
|
nucliadb_utils/tests/nats.py,sha256=xqpww4jZjTKY9oPGlJdDJG67L3FIBQsa9qDHxILR8r8,7687
|
61
61
|
nucliadb_utils/tests/s3.py,sha256=pl-RJFjA4MH6iXkqhsh5g8gDuEhrYu1nPZ-laxlrMlE,3704
|
62
|
-
nucliadb_utils-6.1.0.
|
63
|
-
nucliadb_utils-6.1.0.
|
64
|
-
nucliadb_utils-6.1.0.
|
65
|
-
nucliadb_utils-6.1.0.
|
66
|
-
nucliadb_utils-6.1.0.
|
62
|
+
nucliadb_utils-6.1.0.post2476.dist-info/METADATA,sha256=9xT2in9NaLwz4F16XWog7Kjcx3Udzqz3UlCHKN0dH1U,2055
|
63
|
+
nucliadb_utils-6.1.0.post2476.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
64
|
+
nucliadb_utils-6.1.0.post2476.dist-info/top_level.txt,sha256=fE3vJtALTfgh7bcAWcNhcfXkNPp_eVVpbKK-2IYua3E,15
|
65
|
+
nucliadb_utils-6.1.0.post2476.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
66
|
+
nucliadb_utils-6.1.0.post2476.dist-info/RECORD,,
|
File without changes
|
{nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/top_level.txt
RENAMED
File without changes
|
{nucliadb_utils-6.1.0.post2473.dist-info → nucliadb_utils-6.1.0.post2476.dist-info}/zip-safe
RENAMED
File without changes
|