nebu 0.1.103__py3-none-any.whl → 0.1.104__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.
- nebu/processors/consumer.py +76 -48
- {nebu-0.1.103.dist-info → nebu-0.1.104.dist-info}/METADATA +1 -1
- {nebu-0.1.103.dist-info → nebu-0.1.104.dist-info}/RECORD +6 -6
- {nebu-0.1.103.dist-info → nebu-0.1.104.dist-info}/WHEEL +0 -0
- {nebu-0.1.103.dist-info → nebu-0.1.104.dist-info}/licenses/LICENSE +0 -0
- {nebu-0.1.103.dist-info → nebu-0.1.104.dist-info}/top_level.txt +0 -0
nebu/processors/consumer.py
CHANGED
@@ -609,47 +609,66 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
609
609
|
|
610
610
|
logger.debug(f">> Raw payload: {raw_payload}")
|
611
611
|
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
612
|
+
# --- Extract fields from the *inner* message content for HealthCheck and regular processing ---
|
613
|
+
# The actual message content is inside raw_payload[\"content\"]
|
614
|
+
inner_content_data = raw_payload.get("content", {})
|
615
|
+
if not isinstance(inner_content_data, dict):
|
616
|
+
# If content is not a dict (e.g. already a primitive from a non-Message processor)
|
617
|
+
# we can't reliably get 'kind' or other fields from it.
|
618
|
+
# This case is more relevant for non-StreamMessage processors.
|
619
|
+
# For HealthChecks, we expect a structured 'content'.
|
620
|
+
logger.warning(
|
621
|
+
f"Received non-dict inner_content_data: {inner_content_data}. HealthCheck might be missed if applicable."
|
622
|
+
)
|
623
|
+
inner_kind = "" # Default to empty string
|
624
|
+
inner_msg_id = "" # Default to empty string
|
625
|
+
actual_content_to_process = inner_content_data # Use it as is
|
626
|
+
inner_created_at_str = None
|
627
|
+
else:
|
628
|
+
inner_kind = inner_content_data.get("kind", "")
|
629
|
+
inner_msg_id = inner_content_data.get("id", "")
|
630
|
+
# The 'content' field of the inner_content_data is what the user function expects
|
631
|
+
actual_content_to_process = inner_content_data.get("content", {})
|
632
|
+
inner_created_at_str = inner_content_data.get("created_at")
|
633
|
+
|
634
|
+
# Attempt to parse inner_created_at, fallback to now()
|
617
635
|
try:
|
618
|
-
|
619
|
-
datetime.fromisoformat(
|
620
|
-
if
|
621
|
-
and isinstance(created_at_str, str) # Check type explicitly
|
636
|
+
inner_created_at = (
|
637
|
+
datetime.fromisoformat(inner_created_at_str)
|
638
|
+
if inner_created_at_str and isinstance(inner_created_at_str, str)
|
622
639
|
else datetime.now(timezone.utc)
|
623
640
|
)
|
624
641
|
except ValueError:
|
625
|
-
|
642
|
+
inner_created_at = datetime.now(timezone.utc)
|
626
643
|
|
644
|
+
# These are from the outer envelope, might be useful for routing/meta
|
627
645
|
return_stream = raw_payload.get("return_stream")
|
628
646
|
user_id = raw_payload.get("user_id")
|
629
|
-
orgs = raw_payload.get("organizations")
|
630
|
-
handle = raw_payload.get("handle")
|
631
|
-
adapter = raw_payload.get("adapter")
|
632
|
-
api_key = raw_payload.get("api_key")
|
647
|
+
orgs = raw_payload.get("organizations") # from outer
|
648
|
+
handle = raw_payload.get("handle") # from outer
|
649
|
+
adapter = raw_payload.get("adapter") # from outer
|
650
|
+
api_key = raw_payload.get("api_key") # from outer
|
633
651
|
logger.debug(f">> Extracted API key length: {len(api_key) if api_key else 0}")
|
634
652
|
|
635
|
-
# --- Health Check Logic
|
636
|
-
|
637
|
-
|
653
|
+
# --- Health Check Logic ---
|
654
|
+
# Use inner_kind for health check
|
655
|
+
if inner_kind == "HealthCheck":
|
656
|
+
logger.info(
|
657
|
+
f"Received HealthCheck message {message_id} (inner_id: {inner_msg_id})"
|
658
|
+
)
|
638
659
|
health_response = {
|
639
|
-
"kind": "StreamResponseMessage",
|
640
|
-
"id": message_id,
|
641
|
-
"content": {"status": "healthy", "checked_message_id":
|
660
|
+
"kind": "StreamResponseMessage",
|
661
|
+
"id": message_id, # Use outer message_id for response ID
|
662
|
+
"content": {"status": "healthy", "checked_message_id": inner_msg_id},
|
642
663
|
"status": "success",
|
643
|
-
"created_at": datetime.now().isoformat(),
|
644
|
-
"user_id": user_id,
|
664
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
665
|
+
"user_id": user_id,
|
645
666
|
}
|
646
667
|
if return_stream:
|
647
|
-
# Assert type again closer to usage for type checker clarity
|
648
668
|
assert isinstance(return_stream, str)
|
649
669
|
r.xadd(return_stream, {"data": json.dumps(health_response)})
|
650
670
|
logger.info(f"Sent health check response to {return_stream}")
|
651
671
|
|
652
|
-
# Assert types again closer to usage for type checker clarity
|
653
672
|
assert isinstance(REDIS_STREAM, str)
|
654
673
|
assert isinstance(REDIS_CONSUMER_GROUP, str)
|
655
674
|
r.xack(REDIS_STREAM, REDIS_CONSUMER_GROUP, message_id)
|
@@ -657,16 +676,21 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
657
676
|
return # Exit early for health checks
|
658
677
|
# --- End Health Check Logic ---
|
659
678
|
|
660
|
-
#
|
661
|
-
|
679
|
+
# For non-HealthCheck messages, the content to be processed by user function
|
680
|
+
# is `actual_content_to_process`
|
681
|
+
# The `kind` and `id` for the Message object should be from `inner_content_data`
|
682
|
+
|
683
|
+
# Parse actual_content_to_process if it's a string (e.g., double-encoded JSON)
|
684
|
+
# This might be redundant if actual_content_to_process is already a dict from inner_content_data.get("content")
|
685
|
+
if isinstance(actual_content_to_process, str):
|
662
686
|
try:
|
663
|
-
|
687
|
+
content_for_validation = json.loads(actual_content_to_process)
|
664
688
|
except json.JSONDecodeError:
|
665
|
-
|
689
|
+
content_for_validation = (
|
690
|
+
actual_content_to_process # Keep as string if not valid JSON
|
691
|
+
)
|
666
692
|
else:
|
667
|
-
|
668
|
-
|
669
|
-
# print(f"Content: {content}")
|
693
|
+
content_for_validation = actual_content_to_process
|
670
694
|
|
671
695
|
# --- Construct Input Object using Imported Types ---
|
672
696
|
input_obj: Any = None
|
@@ -712,13 +736,15 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
712
736
|
|
713
737
|
if content_model_class:
|
714
738
|
try:
|
715
|
-
content_model = content_model_class.model_validate(
|
739
|
+
content_model = content_model_class.model_validate(
|
740
|
+
content_for_validation
|
741
|
+
)
|
716
742
|
# print(f"Validated content model: {content_model}")
|
717
743
|
input_obj = message_class(
|
718
|
-
kind=
|
719
|
-
id=
|
744
|
+
kind=inner_kind,
|
745
|
+
id=inner_msg_id,
|
720
746
|
content=content_model,
|
721
|
-
created_at=int(
|
747
|
+
created_at=int(inner_created_at.timestamp()),
|
722
748
|
return_stream=return_stream,
|
723
749
|
user_id=user_id,
|
724
750
|
orgs=orgs,
|
@@ -732,10 +758,10 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
732
758
|
)
|
733
759
|
# Fallback to raw content in Message
|
734
760
|
input_obj = message_class(
|
735
|
-
kind=
|
736
|
-
id=
|
737
|
-
content=cast(Any,
|
738
|
-
created_at=int(
|
761
|
+
kind=inner_kind,
|
762
|
+
id=inner_msg_id,
|
763
|
+
content=cast(Any, content_for_validation),
|
764
|
+
created_at=int(inner_created_at.timestamp()),
|
739
765
|
return_stream=return_stream,
|
740
766
|
user_id=user_id,
|
741
767
|
orgs=orgs,
|
@@ -746,10 +772,10 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
746
772
|
else:
|
747
773
|
# No content type name or class found, use raw content
|
748
774
|
input_obj = message_class(
|
749
|
-
kind=
|
750
|
-
id=
|
751
|
-
content=cast(Any,
|
752
|
-
created_at=int(
|
775
|
+
kind=inner_kind,
|
776
|
+
id=inner_msg_id,
|
777
|
+
content=cast(Any, content_for_validation),
|
778
|
+
created_at=int(inner_created_at.timestamp()),
|
753
779
|
return_stream=return_stream,
|
754
780
|
user_id=user_id,
|
755
781
|
orgs=orgs,
|
@@ -776,21 +802,23 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
776
802
|
logger.warning(
|
777
803
|
f"Warning: Input type class '{param_type_name}' not found. Passing raw content."
|
778
804
|
)
|
779
|
-
input_obj =
|
805
|
+
input_obj = content_for_validation
|
780
806
|
else:
|
781
807
|
logger.debug(f"Found input model class: {input_type_class}")
|
782
|
-
input_obj = input_type_class.model_validate(
|
808
|
+
input_obj = input_type_class.model_validate(
|
809
|
+
content_for_validation
|
810
|
+
)
|
783
811
|
logger.debug(f"Validated input model: {input_obj}")
|
784
812
|
except AttributeError:
|
785
813
|
logger.warning(
|
786
814
|
f"Warning: Input type class '{param_type_name}' not found in imported module."
|
787
815
|
)
|
788
|
-
input_obj =
|
816
|
+
input_obj = content_for_validation
|
789
817
|
except Exception as e:
|
790
818
|
logger.error(
|
791
819
|
f"Error resolving/validating input type '{param_type_name}': {e}. Passing raw content."
|
792
820
|
)
|
793
|
-
input_obj =
|
821
|
+
input_obj = content_for_validation
|
794
822
|
|
795
823
|
except NameError as e:
|
796
824
|
logger.error(
|
@@ -803,7 +831,7 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
803
831
|
raise # Re-raise unexpected errors during input construction
|
804
832
|
|
805
833
|
# print(f"Input object: {input_obj}") # Reduce verbosity
|
806
|
-
|
834
|
+
logger.debug(f"Input object: {input_obj}") # Could use logger.debug if needed
|
807
835
|
|
808
836
|
# Execute the function
|
809
837
|
logger.info("Executing function...")
|
@@ -13,7 +13,7 @@ nebu/containers/container.py,sha256=Mrh_gvMsTvDkj3CwpqIPzJ72IMw0gQIg64y548vq0yg,
|
|
13
13
|
nebu/containers/models.py,sha256=0j6NGy4yto-enRDh_4JH_ZTbHrLdSpuMOqNQPnIrwC4,6815
|
14
14
|
nebu/namespaces/models.py,sha256=EqUOpzhVBhvJw2P92ONDUbIgC31M9jMmcaG5vyOrsWg,497
|
15
15
|
nebu/namespaces/namespace.py,sha256=oeZyGqsIGIrppyjif1ZONsdTmqRgd9oSLFE1BChXTTE,5247
|
16
|
-
nebu/processors/consumer.py,sha256=
|
16
|
+
nebu/processors/consumer.py,sha256=nsh0U1qUoPb2ZgWjT8nIscPLO9RJUzE5xvCGQE93Yic,57289
|
17
17
|
nebu/processors/consumer_process_worker.py,sha256=h--eNFKaLbUayxn88mB8oGGdrU2liE1dnwm_TPlewX8,36960
|
18
18
|
nebu/processors/decorate.py,sha256=AfHVCoNbW7RymccF5ewleEL-GlMiqVH1-t9bCmD60rk,58654
|
19
19
|
nebu/processors/default.py,sha256=cy4ETMdbdRGkrvbYec1o60h7mGDlGN5JsuUph0ENtDU,364
|
@@ -21,8 +21,8 @@ nebu/processors/models.py,sha256=g4B1t6Rgoy-NUEHBLeQc0EENzHXLDlWSio8Muv7cTDU,409
|
|
21
21
|
nebu/processors/processor.py,sha256=vbafqawdZhh5VRoBE5C5wRR_32iSyzoDTqK7qsNQvaM,19242
|
22
22
|
nebu/redis/models.py,sha256=coPovAcVXnOU1Xh_fpJL4PO3QctgK9nBe5QYoqEcnxg,1230
|
23
23
|
nebu/services/service.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
-
nebu-0.1.
|
25
|
-
nebu-0.1.
|
26
|
-
nebu-0.1.
|
27
|
-
nebu-0.1.
|
28
|
-
nebu-0.1.
|
24
|
+
nebu-0.1.104.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
25
|
+
nebu-0.1.104.dist-info/METADATA,sha256=oBCj3SIGECDB3Dt7yBzlHxvh0-gOfMtaMzutDEmeWA8,1798
|
26
|
+
nebu-0.1.104.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
27
|
+
nebu-0.1.104.dist-info/top_level.txt,sha256=uLIbEKJeGSHWOAJN5S0i5XBGwybALlF9bYoB1UhdEgQ,5
|
28
|
+
nebu-0.1.104.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|