nebu 0.1.103__py3-none-any.whl → 0.1.105__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 +105 -51
- {nebu-0.1.103.dist-info → nebu-0.1.105.dist-info}/METADATA +1 -1
- {nebu-0.1.103.dist-info → nebu-0.1.105.dist-info}/RECORD +6 -6
- {nebu-0.1.103.dist-info → nebu-0.1.105.dist-info}/WHEEL +0 -0
- {nebu-0.1.103.dist-info → nebu-0.1.105.dist-info}/licenses/LICENSE +0 -0
- {nebu-0.1.103.dist-info → nebu-0.1.105.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,34 @@ 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(
|
783
|
-
|
808
|
+
input_obj = input_type_class.model_validate(
|
809
|
+
content_for_validation
|
810
|
+
)
|
811
|
+
# Safe logging that avoids __repr__ issues with BaseModel objects
|
812
|
+
try:
|
813
|
+
if hasattr(input_obj, "model_dump"):
|
814
|
+
logger.debug(
|
815
|
+
f"Validated input model (BaseModel): {input_obj.model_dump()}"
|
816
|
+
)
|
817
|
+
else:
|
818
|
+
logger.debug(f"Validated input model: {input_obj}")
|
819
|
+
except Exception as log_e:
|
820
|
+
logger.debug(
|
821
|
+
f"Validated input model: <object of type {type(input_obj).__name__}> (repr failed: {log_e})"
|
822
|
+
)
|
784
823
|
except AttributeError:
|
785
824
|
logger.warning(
|
786
825
|
f"Warning: Input type class '{param_type_name}' not found in imported module."
|
787
826
|
)
|
788
|
-
input_obj =
|
827
|
+
input_obj = content_for_validation
|
789
828
|
except Exception as e:
|
790
829
|
logger.error(
|
791
830
|
f"Error resolving/validating input type '{param_type_name}': {e}. Passing raw content."
|
792
831
|
)
|
793
|
-
input_obj =
|
832
|
+
input_obj = content_for_validation
|
794
833
|
|
795
834
|
except NameError as e:
|
796
835
|
logger.error(
|
@@ -802,13 +841,28 @@ def process_message(message_id: str, message_data: Dict[str, str]) -> None:
|
|
802
841
|
logger.error(f"Error constructing input object: {e}")
|
803
842
|
raise # Re-raise unexpected errors during input construction
|
804
843
|
|
805
|
-
#
|
806
|
-
|
844
|
+
# Safe logging that avoids __repr__ issues with BaseModel objects
|
845
|
+
try:
|
846
|
+
if hasattr(input_obj, "model_dump"):
|
847
|
+
logger.debug(f"Input object (BaseModel): {input_obj.model_dump()}")
|
848
|
+
else:
|
849
|
+
logger.debug(f"Input object: {input_obj}")
|
850
|
+
except Exception as log_e:
|
851
|
+
logger.debug(
|
852
|
+
f"Input object: <object of type {type(input_obj).__name__}> (repr failed: {log_e})"
|
853
|
+
)
|
807
854
|
|
808
855
|
# Execute the function
|
809
856
|
logger.info("Executing function...")
|
810
857
|
result = target_function(input_obj)
|
811
|
-
#
|
858
|
+
# Safe logging that avoids __repr__ issues with BaseModel objects if this debug line is uncommented
|
859
|
+
# try:
|
860
|
+
# if hasattr(result, "model_dump"):
|
861
|
+
# logger.debug(f"Raw Result (BaseModel): {result.model_dump()}")
|
862
|
+
# else:
|
863
|
+
# logger.debug(f"Raw Result: {result}")
|
864
|
+
# except Exception as log_e:
|
865
|
+
# logger.debug(f"Raw Result: <object of type {type(result).__name__}> (repr failed: {log_e})")
|
812
866
|
|
813
867
|
result_content = None # Default to None
|
814
868
|
if result is not None: # Only process if there's a result
|
@@ -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=v5JsuvEEUUBbe8sKGB2QjHca8FPHMIjq9Ntk32Uf3G4,58674
|
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.105.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
25
|
+
nebu-0.1.105.dist-info/METADATA,sha256=B9wVIWPowGZHwobFzrRBymh14aUiwL_GAFTNRR80roo,1798
|
26
|
+
nebu-0.1.105.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
27
|
+
nebu-0.1.105.dist-info/top_level.txt,sha256=uLIbEKJeGSHWOAJN5S0i5XBGwybALlF9bYoB1UhdEgQ,5
|
28
|
+
nebu-0.1.105.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|