8
8
use crate :: kafka_config:: PyKafkaConsumerConfig ;
9
9
use crate :: operators:: build;
10
10
use crate :: operators:: RuntimeOperator ;
11
+ use crate :: routes:: Route ;
12
+ use crate :: routes:: RoutedValue ;
11
13
use pyo3:: prelude:: * ;
12
14
use pyo3:: types:: PyBytes ;
13
15
use sentry_arroyo:: backends:: kafka:: types:: KafkaPayload ;
@@ -39,6 +41,8 @@ pub struct ArroyoConsumer {
39
41
40
42
topic : String ,
41
43
44
+ source : String ,
45
+
42
46
steps : Vec < Py < RuntimeOperator > > ,
43
47
44
48
/// The ProcessorHandle allows the main thread to stop the StreamingProcessor
@@ -49,10 +53,11 @@ pub struct ArroyoConsumer {
49
53
#[ pymethods]
50
54
impl ArroyoConsumer {
51
55
#[ new]
52
- fn new ( kafka_config : PyKafkaConsumerConfig , topic : String ) -> Self {
56
+ fn new ( source : String , kafka_config : PyKafkaConsumerConfig , topic : String ) -> Self {
53
57
ArroyoConsumer {
54
58
consumer_config : kafka_config,
55
59
topic,
60
+ source,
56
61
steps : Vec :: new ( ) ,
57
62
handle : None ,
58
63
}
@@ -77,7 +82,10 @@ impl ArroyoConsumer {
77
82
. map ( |step| step. clone_ref ( py) )
78
83
. collect :: < Vec < _ > > ( )
79
84
} ) ;
80
- let factory = ArroyoStreamingFactory { steps : steps_copy } ;
85
+ let factory = ArroyoStreamingFactory {
86
+ source : self . source . clone ( ) ,
87
+ steps : steps_copy,
88
+ } ;
81
89
let config = self . consumer_config . clone ( ) . into ( ) ;
82
90
let processor = StreamProcessor :: with_kafka ( config, factory, Topic :: new ( & self . topic ) , None ) ;
83
91
self . handle = Some ( processor. get_handle ( ) ) ;
@@ -89,7 +97,7 @@ impl ArroyoConsumer {
89
97
} )
90
98
. expect ( "Error setting Ctrl+C handler" ) ;
91
99
92
- processor. run ( ) ;
100
+ let _ = processor. run ( ) ;
93
101
}
94
102
95
103
fn shutdown ( & mut self ) {
@@ -103,40 +111,45 @@ impl ArroyoConsumer {
103
111
/// Converts a Message<KafkaPayload> to a Message<Py<PyAny>>.
104
112
/// It takes the Kafka payload as bytes and turns it into a
105
113
/// Python bytes object.
106
- fn to_python ( message : Message < KafkaPayload > ) -> Message < Py < PyAny > > {
107
- let payload = Python :: with_gil ( |py| {
108
- let payload = message. payload ( ) . payload ( ) . unwrap ( ) ;
109
- let py_bytes = PyBytes :: new ( py, payload) ;
110
- py_bytes. into_any ( ) . unbind ( )
114
+ fn to_python ( source : & str , message : Message < KafkaPayload > ) -> Message < RoutedValue > {
115
+ let payload = Python :: with_gil ( |py| match message. payload ( ) . payload ( ) {
116
+ Some ( payload) => PyBytes :: new ( py, payload) . into_any ( ) . unbind ( ) ,
117
+ None => py. None ( ) ,
111
118
} ) ;
112
- message. replace ( payload)
119
+ let route = Route :: new ( source. to_string ( ) , vec ! [ ] ) ;
120
+ message. replace ( RoutedValue { route, payload } )
113
121
}
114
122
115
123
/// Builds the Arroyo StreamProcessor for this consumer.
116
124
/// It plugs a Commit policy at the end and a translator at the beginning
117
125
/// that takes the payload of the Kafka message and turns it into a Py<PyAny>
118
- fn build_chain ( steps : & [ Py < RuntimeOperator > ] ) -> Box < dyn ProcessingStrategy < KafkaPayload > > {
119
- let mut next: Box < dyn ProcessingStrategy < Py < PyAny > > > =
126
+ fn build_chain (
127
+ source : & str ,
128
+ steps : & [ Py < RuntimeOperator > ] ,
129
+ ) -> Box < dyn ProcessingStrategy < KafkaPayload > > {
130
+ let mut next: Box < dyn ProcessingStrategy < RoutedValue > > =
120
131
Box :: new ( CommitOffsets :: new ( Duration :: from_secs ( 5 ) ) ) ;
121
132
for step in steps. iter ( ) . rev ( ) {
122
133
next = build ( step, next) ;
123
134
}
124
135
125
- let converter = RunTask :: new (
126
- |message : Message < KafkaPayload > | Ok ( to_python ( message) ) ,
127
- next,
128
- ) ;
136
+ let copied_source = source. to_string ( ) ;
137
+ let conversion_function =
138
+ move |message : Message < KafkaPayload > | Ok ( to_python ( & copied_source, message) ) ;
139
+
140
+ let converter = RunTask :: new ( conversion_function, next) ;
129
141
130
142
Box :: new ( converter)
131
143
}
132
144
133
145
struct ArroyoStreamingFactory {
146
+ source : String ,
134
147
steps : Vec < Py < RuntimeOperator > > ,
135
148
}
136
149
137
150
impl ProcessingStrategyFactory < KafkaPayload > for ArroyoStreamingFactory {
138
151
fn create ( & self ) -> Box < dyn ProcessingStrategy < KafkaPayload > > {
139
- build_chain ( & self . steps )
152
+ build_chain ( & self . source , & self . steps )
140
153
}
141
154
}
142
155
#[ cfg( test) ]
@@ -167,6 +180,20 @@ mod tests {
167
180
} ) ;
168
181
}
169
182
183
+ #[ test]
184
+ fn test_to_none_python ( ) {
185
+ Python :: with_gil ( |py| {
186
+ let message =
187
+ Message :: new_any_message ( KafkaPayload :: new ( None , None , None ) , BTreeMap :: new ( ) ) ;
188
+
189
+ let python_message = to_python ( message) ;
190
+
191
+ let py_payload = python_message. payload ( ) ;
192
+
193
+ assert ! ( py_payload. is_none( py) ) ;
194
+ } ) ;
195
+ }
196
+
170
197
#[ test]
171
198
fn test_build_chain ( ) {
172
199
Python :: with_gil ( |py| {
0 commit comments