nebu 0.1.19__py3-none-any.whl → 0.1.20__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.
@@ -6,10 +6,11 @@ import sys
6
6
  import time
7
7
  import traceback
8
8
  from datetime import datetime
9
- from typing import Dict, TypeVar
9
+ from typing import Any, Dict, TypeVar, cast
10
10
 
11
11
  import redis
12
12
  import socks
13
+ from redis import ConnectionError, ResponseError
13
14
 
14
15
  # Define TypeVar for generic models
15
16
  T = TypeVar("T")
@@ -247,7 +248,7 @@ except Exception as e:
247
248
  try:
248
249
  r.xgroup_create(REDIS_STREAM, REDIS_CONSUMER_GROUP, id="0", mkstream=True)
249
250
  print(f"Created consumer group {REDIS_CONSUMER_GROUP} for stream {REDIS_STREAM}")
250
- except redis.exceptions.ResponseError as e:
251
+ except ResponseError as e:
251
252
  if "BUSYGROUP" in str(e):
252
253
  print(f"Consumer group {REDIS_CONSUMER_GROUP} already exists")
253
254
  else:
@@ -262,25 +263,19 @@ def process_message(message_id: bytes, message_data: Dict[bytes, bytes]) -> None
262
263
  user_id = None
263
264
 
264
265
  try:
265
- # Check for and decode the 'data' field
266
- data_bytes = message_data.get(b"data")
267
- if data_bytes is None:
268
- # Raise an error if 'data' field is missing
269
- raise ValueError("Message missing 'data' field")
266
+ # Assign message_data directly to raw_payload.
267
+ # Cast to Dict[str, Any] to inform type checker of the expected type due to decode_responses=True.
268
+ raw_payload = cast(Dict[str, Any], message_data)
270
269
 
271
- try:
272
- # Decode bytes to string and parse JSON
273
- raw_payload_str = data_bytes.decode("utf-8")
274
- raw_payload = json.loads(raw_payload_str)
275
- except (json.JSONDecodeError, UnicodeDecodeError) as decode_error:
276
- # Raise a specific error for decoding/parsing issues
277
- raise ValueError(f"Invalid JSON payload: {decode_error}") from decode_error
270
+ # Validate that raw_payload is a dictionary as expected - Removed, cast handles this for type checker
271
+ # if not isinstance(raw_payload, dict):
272
+ # raise TypeError(f"Expected message_data to be a dictionary, but got {type(raw_payload)}")
278
273
 
279
274
  print(f"Raw payload: {raw_payload}")
280
275
 
281
276
  # Extract fields from the parsed payload
282
277
  # These fields are extracted for completeness and potential future use
283
- _ = raw_payload.get("kind", "") # kind
278
+ kind = raw_payload.get("kind", "") # kind
284
279
  msg_id = raw_payload.get("id", "") # msg_id
285
280
  content_raw = raw_payload.get("content", {})
286
281
  created_at = raw_payload.get("created_at", 0) # created_at
@@ -290,6 +285,31 @@ def process_message(message_id: bytes, message_data: Dict[bytes, bytes]) -> None
290
285
  handle = raw_payload.get("handle") # handle
291
286
  adapter = raw_payload.get("adapter") # adapter
292
287
 
288
+ # --- Health Check Logic based on kind ---
289
+ if kind == "HealthCheck":
290
+ print(f"Received HealthCheck message {message_id.decode('utf-8')}")
291
+ health_response = {
292
+ "kind": "StreamResponseMessage", # Respond with a standard message kind
293
+ "id": message_id.decode("utf-8"),
294
+ "content": {"status": "healthy", "checked_message_id": msg_id},
295
+ "status": "success",
296
+ "created_at": datetime.now().isoformat(),
297
+ "user_id": user_id, # Include user_id if available
298
+ }
299
+ if return_stream:
300
+ # Assert type again closer to usage for type checker clarity
301
+ assert isinstance(return_stream, str)
302
+ r.xadd(return_stream, {"data": json.dumps(health_response)})
303
+ print(f"Sent health check response to {return_stream}")
304
+
305
+ # Assert types again closer to usage for type checker clarity
306
+ assert isinstance(REDIS_STREAM, str)
307
+ assert isinstance(REDIS_CONSUMER_GROUP, str)
308
+ r.xack(REDIS_STREAM, REDIS_CONSUMER_GROUP, message_id)
309
+ print(f"Acknowledged HealthCheck message {message_id.decode('utf-8')}")
310
+ return # Exit early for health checks
311
+ # --- End Health Check Logic ---
312
+
293
313
  # Parse the content field if it's a string
294
314
  if isinstance(content_raw, str):
295
315
  try:
@@ -310,7 +330,7 @@ def process_message(message_id: bytes, message_data: Dict[bytes, bytes]) -> None
310
330
  content_model = local_namespace[content_type_name](**content)
311
331
  print(f"Content model: {content_model}")
312
332
  input_obj = local_namespace["V1StreamMessage"](
313
- kind=_,
333
+ kind=kind,
314
334
  id=msg_id,
315
335
  content=content_model,
316
336
  created_at=created_at,
@@ -324,7 +344,7 @@ def process_message(message_id: bytes, message_data: Dict[bytes, bytes]) -> None
324
344
  print(f"Error creating content type model: {e}")
325
345
  # Fallback to using raw content
326
346
  input_obj = local_namespace["V1StreamMessage"](
327
- kind=_,
347
+ kind=kind,
328
348
  id=msg_id,
329
349
  content=content,
330
350
  created_at=created_at,
@@ -338,7 +358,7 @@ def process_message(message_id: bytes, message_data: Dict[bytes, bytes]) -> None
338
358
  # Just use the raw content
339
359
  print(f"Using raw content")
340
360
  input_obj = local_namespace["V1StreamMessage"](
341
- kind=_,
361
+ kind=kind,
342
362
  id=msg_id,
343
363
  content=content,
344
364
  created_at=created_at,
@@ -383,12 +403,17 @@ def process_message(message_id: bytes, message_data: Dict[bytes, bytes]) -> None
383
403
 
384
404
  # Send the result to the return stream
385
405
  if return_stream:
406
+ # Assert type again closer to usage for type checker clarity
407
+ assert isinstance(return_stream, str)
386
408
  r.xadd(return_stream, {"data": json.dumps(response)})
387
409
  print(
388
410
  f"Processed message {message_id.decode('utf-8')}, result sent to {return_stream}"
389
411
  )
390
412
 
391
413
  # Acknowledge the message
414
+ # Assert types again closer to usage for type checker clarity
415
+ assert isinstance(REDIS_STREAM, str)
416
+ assert isinstance(REDIS_CONSUMER_GROUP, str)
392
417
  r.xack(REDIS_STREAM, REDIS_CONSUMER_GROUP, message_id)
393
418
 
394
419
  except Exception as e:
@@ -410,11 +435,18 @@ def process_message(message_id: bytes, message_data: Dict[bytes, bytes]) -> None
410
435
 
411
436
  # Send the error to the return stream
412
437
  if return_stream:
438
+ # Assert type again closer to usage for type checker clarity
439
+ assert isinstance(return_stream, str)
413
440
  r.xadd(return_stream, {"data": json.dumps(error_response)})
414
441
  else:
442
+ # Assert type again closer to usage for type checker clarity
443
+ assert isinstance(REDIS_STREAM, str)
415
444
  r.xadd(f"{REDIS_STREAM}.errors", {"data": json.dumps(error_response)})
416
445
 
417
446
  # Still acknowledge the message so we don't reprocess it
447
+ # Assert types again closer to usage for type checker clarity
448
+ assert isinstance(REDIS_STREAM, str)
449
+ assert isinstance(REDIS_CONSUMER_GROUP, str)
418
450
  r.xack(REDIS_STREAM, REDIS_CONSUMER_GROUP, message_id)
419
451
 
420
452
 
@@ -424,9 +456,13 @@ consumer_name = f"consumer-{os.getpid()}"
424
456
 
425
457
  while True:
426
458
  try:
459
+ # Assert types just before use in the loop
460
+ assert isinstance(REDIS_STREAM, str)
461
+ assert isinstance(REDIS_CONSUMER_GROUP, str)
462
+
427
463
  # Read from stream with blocking
428
464
  streams = {REDIS_STREAM: ">"} # '>' means read only new messages
429
- messages = r.xreadgroup(
465
+ messages = r.xreadgroup( # type: ignore[arg-type]
430
466
  REDIS_CONSUMER_GROUP, consumer_name, streams, count=1, block=5000
431
467
  )
432
468
 
@@ -434,6 +470,12 @@ while True:
434
470
  # No messages received, continue waiting
435
471
  continue
436
472
 
473
+ # Assert that messages is a list (expected synchronous return type)
474
+ assert isinstance(
475
+ messages, list
476
+ ), f"Expected list from xreadgroup, got {type(messages)}"
477
+ assert len(messages) > 0 # Ensure the list is not empty before indexing
478
+
437
479
  stream_name, stream_messages = messages[0]
438
480
 
439
481
  for message_id, message_data in stream_messages:
@@ -441,7 +483,7 @@ while True:
441
483
  print(f"Message data: {message_data}")
442
484
  process_message(message_id, message_data)
443
485
 
444
- except redis.exceptions.ConnectionError as e:
486
+ except ConnectionError as e:
445
487
  print(f"Redis connection error: {e}")
446
488
  time.sleep(5) # Wait before retrying
447
489
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nebu
3
- Version: 0.1.19
3
+ Version: 0.1.20
4
4
  Summary: A globally distributed container runtime
5
5
  Requires-Python: >=3.10.14
6
6
  Description-Content-Type: text/markdown
@@ -6,15 +6,15 @@ nebu/containers/container.py,sha256=yb7KaPTVXnEEAlrpdlUi4HNqF6P7z9bmwAILGlq6iqU,
6
6
  nebu/containers/decorator.py,sha256=uFtzlAXRHYZECJ-NPusY7oN9GXvdHrHDd_JNrIGr8aQ,3244
7
7
  nebu/containers/models.py,sha256=0j6NGy4yto-enRDh_4JH_ZTbHrLdSpuMOqNQPnIrwC4,6815
8
8
  nebu/containers/server.py,sha256=yFa2Y9PzBn59E1HftKiv0iapPonli2rbGAiU6r-wwe0,2513
9
- nebu/processors/consumer.py,sha256=EbOhoFogS3W91BmJjqrFeipX_2G7lgAuUVGOpemcswM,16844
9
+ nebu/processors/consumer.py,sha256=kX4UT8Z5c_LWU3MOcM5qXSzHEA0CYjUZ4dRJfhUKP-M,19202
10
10
  nebu/processors/decorate.py,sha256=AeG1c1n8JtcexxAEf2sF2L2eKwVDaNQ5gvPs6EpazKo,34789
11
11
  nebu/processors/default.py,sha256=W4slJenG59rvyTlJ7gRp58eFfXcNOTT2Hfi6zzJAobI,365
12
12
  nebu/processors/models.py,sha256=GvnI8UJrQSjHo2snP07cPfisCH90cEGTY-PZV5_AtXI,3654
13
13
  nebu/processors/processor.py,sha256=oy2YdI-cy6qQWxrZhpZahJV46oWZlu_Im-jm811R_oo,9667
14
14
  nebu/redis/models.py,sha256=coPovAcVXnOU1Xh_fpJL4PO3QctgK9nBe5QYoqEcnxg,1230
15
15
  nebu/services/service.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- nebu-0.1.19.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
17
- nebu-0.1.19.dist-info/METADATA,sha256=soUNeXLW9Ikz2heD7RSSeiUW8Rut2Q9bK-P9rAuwnes,1678
18
- nebu-0.1.19.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
19
- nebu-0.1.19.dist-info/top_level.txt,sha256=uLIbEKJeGSHWOAJN5S0i5XBGwybALlF9bYoB1UhdEgQ,5
20
- nebu-0.1.19.dist-info/RECORD,,
16
+ nebu-0.1.20.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
17
+ nebu-0.1.20.dist-info/METADATA,sha256=mmrQRfaJ6jXFMa02a7rp4ghX1wKW8m3TLHeBCsmk64g,1678
18
+ nebu-0.1.20.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
19
+ nebu-0.1.20.dist-info/top_level.txt,sha256=uLIbEKJeGSHWOAJN5S0i5XBGwybALlF9bYoB1UhdEgQ,5
20
+ nebu-0.1.20.dist-info/RECORD,,
File without changes